From a0f08c22e1e6a1c2cf7efd134cd9b6250a8abb36 Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Mon, 29 Jul 2024 17:03:28 +0200 Subject: [PATCH 01/53] add dev-postgres-powersync environment --- dev-postgres-powersync/.env | 20 ++++ .../config-powersync/powersync.yaml | 97 +++++++++++++++++++ .../config-powersync/sync_rules.yaml | 11 +++ dev-postgres-powersync/docker-compose.yml | 66 +++++++++++++ .../powersync-services/mongo.yaml | 24 +++++ .../powersync-services/powersync.yaml | 73 ++++++++++++++ 6 files changed, 291 insertions(+) create mode 100644 dev-postgres-powersync/.env create mode 100644 dev-postgres-powersync/config-powersync/powersync.yaml create mode 100644 dev-postgres-powersync/config-powersync/sync_rules.yaml create mode 100644 dev-postgres-powersync/docker-compose.yml create mode 100644 dev-postgres-powersync/powersync-services/mongo.yaml create mode 100644 dev-postgres-powersync/powersync-services/powersync.yaml diff --git a/dev-postgres-powersync/.env b/dev-postgres-powersync/.env new file mode 100644 index 000000000..fff5f23fa --- /dev/null +++ b/dev-postgres-powersync/.env @@ -0,0 +1,20 @@ +# ==================== Postgres credentials ================================ +PG_DATABASE_NAME=wger +PG_DATABASE_PORT=5432 +PG_DATABASE_USER=wger +PG_DATABASE_PASSWORD=wger + +# ==================== Demo config ========================================= +DEMO_BACKEND_PORT=6061 +# The front-end demo application is accessible at this port on the host machine +DEMO_CLIENT_PORT=3030 +PS_JWKS_URL=http://demo-backend:${DEMO_BACKEND_PORT}/api/get_keys/ + +# These can be generated by following the instructions in the `key-generator` folder +# A temporary key will be used if these are not specified +DEMO_JWKS_PUBLIC_KEY= +DEMO_JWKS_PRIVATE_KEY= + +# ==================== PowerSync variables ==================== +# The PowerSync API is accessible via this port +PS_PORT=8080 diff --git a/dev-postgres-powersync/config-powersync/powersync.yaml b/dev-postgres-powersync/config-powersync/powersync.yaml new file mode 100644 index 000000000..4ff147957 --- /dev/null +++ b/dev-postgres-powersync/config-powersync/powersync.yaml @@ -0,0 +1,97 @@ +# 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 + + # Required for verify-ca, optional for verify-full + # cacert: ${PS_PG_CA_CERT} + + # Include a certificate here for HTTPs + # client_certificate: ${PS_PG_CLIENT_CERT} + # client_private_key: ${PS_PG_CLIENT_PRIVATE_KEY} + +# This is valid if using the `mongo` service defined in `ps-mongo.yaml` + +# Connection settings for sync bucket storage +storage: + type: mongodb + uri: !env PS_MONGO_URI + # Use these if authentication is required. The user should have `readWrite` and `dbAdmin` roles + # username: my-mongo-user + # password: my-password + +# 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 + + # JWKS URIs can be specified here + jwks_uri: !env PS_JWKS_URL + + # Optional static collection of public keys for JWT verification + # jwks: + # keys: + # - kty: 'RSA' + # n: '${PS_JWK_N}' + # e: '${PS_JWK_E}' + # alg: 'RS256' + # kid: '${PS_JWK_KID}' + + # JWKS audience + audience: ["powersync-dev", "powersync"] diff --git a/dev-postgres-powersync/config-powersync/sync_rules.yaml b/dev-postgres-powersync/config-powersync/sync_rules.yaml new file mode 100644 index 000000000..6a1cc21f0 --- /dev/null +++ b/dev-postgres-powersync/config-powersync/sync_rules.yaml @@ -0,0 +1,11 @@ +# 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. +bucket_definitions: + user_lists: + # Separate bucket per todo list + parameters: select id as list_id from lists where owner_id = token_parameters.user_id + data: + - select * from lists where id = bucket.list_id + - select * from todos where list_id = bucket.list_id diff --git a/dev-postgres-powersync/docker-compose.yml b/dev-postgres-powersync/docker-compose.yml new file mode 100644 index 000000000..b8bfd291f --- /dev/null +++ b/dev-postgres-powersync/docker-compose.yml @@ -0,0 +1,66 @@ +name: wger-dev-postgres-powersync + +services: + web: + image: wger/server:powersync + depends_on: + db: + condition: service_healthy + env_file: + - ../config/prod.env + - ../config/dev.env + # django backend should do some powersync stuff.. + environment: + # From the PowerSync service name + # This is just used to populate the JWT audience + POWERSYNC_URL: powersync-dev + + # Keys here for demonstration + POWERSYNC_PUBLIC_KEY: ${DEMO_JWKS_PUBLIC_KEY} + POWERSYNC_PRIVATE_KEY: ${DEMO_JWKS_PRIVATE_KEY} + volumes: + - type: bind + source: /home/dieter/code/wger-wger + target: /home/wger/src + ports: + - "8000:8000" + + cache: + image: redis + expose: + - 6379 + healthcheck: + test: redis-cli ping + interval: 10s + timeout: 5s + retries: 5 + start_period: 30s + restart: unless-stopped + + db: + image: postgres:15-alpine + environment: + - POSTGRES_USER=wger + - POSTGRES_PASSWORD=wger + - POSTGRES_DB=wger + volumes: + - postgres-data:/var/lib/postgresql/data/ + ports: + - "5432:5432" + expose: + - 5432 + 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-data: + +include: + - path: powersync-services/mongo.yaml + - path: powersync-services/powersync.yaml diff --git a/dev-postgres-powersync/powersync-services/mongo.yaml b/dev-postgres-powersync/powersync-services/mongo.yaml new file mode 100644 index 000000000..e01283655 --- /dev/null +++ b/dev-postgres-powersync/powersync-services/mongo.yaml @@ -0,0 +1,24 @@ +services: + # MongoDB Service used internally + mongo: + image: mongo:7.0 + command: --replSet rs0 --bind_ip_all --quiet + restart: unless-stopped + ports: + - 27017:27017 + volumes: + - mongo_storage:/data/db + + # Initializes the MongoDB replica set. This service will not usually be actively running + mongo-rs-init: + image: mongo:7.0 + depends_on: + - mongo + restart: on-failure + entrypoint: + - bash + - -c + - 'mongosh --host mongo:27017 --eval ''try{rs.status().ok && quit(0)} catch {} rs.initiate({_id: "rs0", version: 1, members: [{ _id: 0, host : "mongo:27017" }]})''' + +volumes: + mongo_storage: diff --git a/dev-postgres-powersync/powersync-services/powersync.yaml b/dev-postgres-powersync/powersync-services/powersync.yaml new file mode 100644 index 000000000..85212dc5f --- /dev/null +++ b/dev-postgres-powersync/powersync-services/powersync.yaml @@ -0,0 +1,73 @@ +services: + powersync: + depends_on: + mongo-rs-init: + condition: service_completed_successfully + restart: unless-stopped + image: journeyapps/powersync-service:latest + # The unified service runs an API server and replication worker in the same container. + # These services can be executed in different containers by using individual entry commands e.g. + # Start only the API server with + # command: ['start', '-r', 'api'] + # Start only the replication worker with + # command: ['start', '-r', 'sync'] + + # Migations occur automatically by default. Default migrations can be disabled in `powersync.yaml`: + # migrations: + # disable_auto_migration: true + # + # Service migrations can be manually triggered by starting a container with the + # following command: + # command: ['migrate', 'up'] + # Note that this container must finish executing before starting the sync or unified container. + command: ["start", "-r", "unified"] + volumes: + # Mounts the specified config folder to the container + # This folder should contain `powersync.yaml and sync_rules.yaml + - ../config-powersync:/config + environment: + # This is the path (inside the container) to the YAML config file + # Alternatively the config path can be specified in the command + # e.g: + # command: ['start', '-r', 'unified', '-c', '/config/powersync.yaml'] + # + # The config file can also be specified in Base 64 encoding + # e.g.: Via an environment variable + # POWERSYNC_CONFIG_B64: [base64 encoded content] + # or e.g.: Via a command line parameter + # command: ['start', '-r', 'unified', '-c64', '[base64 encoded content]'] + POWERSYNC_CONFIG_PATH: /config/powersync.yaml + + # Sync rules can be specified as base 64 encoded YAML + # e.g: Via an environment variable + # POWERSYNC_SYNC_RULES_B64: "[base64 encoded sync rules]" + # or e.g.: Via a command line parameter + # command: ['start', '-r', 'unified', '-sync64', '[base64 encoded content]'] + + # The following will be inserted into the powersync.yaml file via templating + # Templates are used for filesystem and base64 configuration files + PS_PG_URI: postgres://${PG_DATABASE_USER}:${PG_DATABASE_PASSWORD}@db:${PG_DATABASE_PORT}/${PG_DATABASE_NAME} + PS_MONGO_URI: mongodb://mongo:27017/powersync_demo + + # Note that powersync.yaml->client_auth->allow_local_jwks must be true for local URLs to work + PS_JWKS_URL: ${PS_JWKS_URL} + + # The port which the PowerSync API server should run on + PS_PORT: ${PS_PORT} + + # CA certificate for Postgres connection + # PS_PG_CA_CERT: + + # Client certificate for Postgres connection + # PS_PG_CLIENT_CERT: + + # Client private key for Postgres connection + # PS_PG_CLIENT_PRIVATE_KEY: + + # Potential JWKs public key template + # PS_JWK_N: + # PS_JWK_E: + # PS_JWK_KID: + + ports: + - ${PS_PORT}:${PS_PORT} From 6a23da8f6108b2583b0db847ac002d098d813712 Mon Sep 17 00:00:00 2001 From: Roland Geider Date: Sun, 11 Aug 2024 17:12:24 +0200 Subject: [PATCH 02/53] Add a test powersync key pair --- dev-postgres-powersync/.env | 11 ++++------- .../config-powersync/powersync.yaml | 11 ----------- .../config-powersync/sync_rules.yaml | 14 +++++++++----- dev-postgres-powersync/docker-compose.yml | 8 ++------ .../powersync-services/powersync.yaml | 9 --------- 5 files changed, 15 insertions(+), 38 deletions(-) diff --git a/dev-postgres-powersync/.env b/dev-postgres-powersync/.env index fff5f23fa..cf902a97f 100644 --- a/dev-postgres-powersync/.env +++ b/dev-postgres-powersync/.env @@ -4,16 +4,13 @@ PG_DATABASE_PORT=5432 PG_DATABASE_USER=wger PG_DATABASE_PASSWORD=wger -# ==================== Demo config ========================================= -DEMO_BACKEND_PORT=6061 -# The front-end demo application is accessible at this port on the host machine -DEMO_CLIENT_PORT=3030 -PS_JWKS_URL=http://demo-backend:${DEMO_BACKEND_PORT}/api/get_keys/ +PS_JWKS_URL=http://web:8000/api/v2/powersync-keys # These can be generated by following the instructions in the `key-generator` folder # A temporary key will be used if these are not specified -DEMO_JWKS_PUBLIC_KEY= -DEMO_JWKS_PRIVATE_KEY= +# --> keys generated with https://github.com/powersync-ja/powersync-jwks-example/blob/main/README.md +POWERSYNC_JWKS_PUBLIC_KEY=eyJrdHkiOiJSU0EiLCJuIjoienNsem9lajhpdFZIR3BWRXYySUtqSU5ORmVUZ1R4X0NRcF9lc2Q4S0VrQ3ZjQXMtSXVpNmw5WXQ1VUNKb2Vmemo5Nmp5Z3FxS0JzUFdLSC1hOXlHdnd6NmRZZ1hqWkdlRUozUXc0UWxxYjhoNlotVU1FeXFGWlVUNUN6d0RiTTBkM1BiVEVJTGJhNnRldHhHNlN2cldwVU5HVnBZczN0SXdVaEdEcGd0RnM5UV91YXRhb0dhcUpRa0pXWTJ1SkhqRHFOQVpEVjliazBzYmhYcnI3dnZoeXVaYVRBZngtNWVCZktSd1FWcGtCRzhabWZHbVNGMnVtWmhpVUhNOUhRYW5zN1ZoWS1ISm5CbFpoNjVhMGpkbncwaHFiX0REaDJSRWNfZktmSmg1UkloZ19zQzBrT29hWjZNS29GOXl0QUNsN0FxdXFlNHZBcEJDUG1aV21KVTZ3IiwiZSI6IkFRQUIiLCJhbGciOiJSUzI1NiIsImtpZCI6InBvd2Vyc3luYy1iNGUwMTMzN2Q3In0= +POWERSYNC_JWKS_PRIVATE_KEY=eyJrdHkiOiJSU0EiLCJuIjoienNsem9lajhpdFZIR3BWRXYySUtqSU5ORmVUZ1R4X0NRcF9lc2Q4S0VrQ3ZjQXMtSXVpNmw5WXQ1VUNKb2Vmemo5Nmp5Z3FxS0JzUFdLSC1hOXlHdnd6NmRZZ1hqWkdlRUozUXc0UWxxYjhoNlotVU1FeXFGWlVUNUN6d0RiTTBkM1BiVEVJTGJhNnRldHhHNlN2cldwVU5HVnBZczN0SXdVaEdEcGd0RnM5UV91YXRhb0dhcUpRa0pXWTJ1SkhqRHFOQVpEVjliazBzYmhYcnI3dnZoeXVaYVRBZngtNWVCZktSd1FWcGtCRzhabWZHbVNGMnVtWmhpVUhNOUhRYW5zN1ZoWS1ISm5CbFpoNjVhMGpkbncwaHFiX0REaDJSRWNfZktmSmg1UkloZ19zQzBrT29hWjZNS29GOXl0QUNsN0FxdXFlNHZBcEJDUG1aV21KVTZ3IiwiZSI6IkFRQUIiLCJkIjoiUTJtUEpjaGpsQXNGZkJnUGFtalcwWW40ZGx1Xy1HdDlFLVUwWHo0NzlVbGJLQ2F5SWdWRzF6ci1pVThwenp0anZwSXhTU3VDMzBJN0ZZVHlBVTNLSzd4YVpqaHduVGxNazFRdmU1MjNfWWVPMGEteFNyR2pmUmUxZlZ4ZEFjcGJIMW9Jc3VxUS1UZkozRlMxVlV4NUZIV2s2SV80Zk1LRExHZVlWeWVyQTFVS1NXZUoxYThjeUhLSTVCOUVyNkhKaGVYb1NDTVhYeS1rRFd1em1Sclp3TGVzd0g3SHI4d00wRXdfTUN4MnA3NUU2bU8zZnBlcUZKV1dwSGZqV2ZoVGp0RkVBOHVPMGd6dGdJSzlhbkVSV1FhMEx4b29NZ2E0TDczRFFYMFNyczFZdTQwYlJ2WWZJY3k2ZThFc2M2eFFjYkZtV29mVWlneEZJODZ1bXdIQktRIiwicCI6Ijl2aVNpOE9ueG1nVlVFZW5aLVhoa0haVHh2V2NGZjI5YWVYYVhHVGtMTlBzMHBMRFFZd01lWGFTandaUk5FQngxR2tPQ1I5dEFoV3JRNWxBaW5MeHNxX1JFT2VQajA0QTJ2U2RNQnIybWJuM2lxT0htaE9iQXhPOUd4OHdWNWt4V255YnJkeGE0dkRtdmV6QkJqaEdfYS1XenhMSUZSNUw4Q3dPd1R2UkRNMCIsInEiOiIxbGpLMWh6Nzh1aGYyWHBjNmw4T0FueFRxbnlYQ1pkM3VJQ1hTSW9wMXlXaVlSVWxVZk9EVW1XWG8yVE93RHIzM0Joc091YktBT3FSTm1Gc0ZWaTgzM1JVMjFXeFBOVHRqUllSRzYteHFId0NfYlBFQTAzbExYNkM0aVo3R254aHRpN2JEX0UxRy1OaXBRZFNHOEVwTEFwYnFzTmUzWTA0NUVSbzdaaGk2SmMiLCJkcCI6InZmQ1FyR01PanA0UF9rME5aLS01bWVRWExJWkt3X01CRVFmUTk0dzBuSEZreXRKS3p3ZUp0SVRIMUszVUdDNlVIUHVxNnNNN2tBWGdVTDMxa0VVMHMtdGFDX2s3Uk1pR0NkOWxZTkRyNVhETC05a20tZzJvQXliVUlwN0xEQ1BxZkNBbmp3QlEtZ2F5UDFGdFpuNHp3dm1mTDZUUE1zYTVPbjUzM285RmlPVSIsImRxIjoicmRTU292UWNpOUZTTWxBZTNGLThQOTNPQ0Z4RUxSNHVsRzJNd3VKeHJpNnlNbU53d2JabjBNSGRLVUNPdjZ6UzZDYlNWeTVsc2pxSkMzNFVwbmN4clZKdG92Y3E1cmVUOHpCckxYWGQ4VktwSmxETWJSV1ZfOEF5cXU4a05NV2NoS0FaUGlPU3U0dzdxclIyTFZZSWF0UDNwVlFPTWtUZVY1ajNNNEM2N2Y4IiwicWkiOiJOM3RDNm1RbHZkcVdEVVh1b2MtT1Mteno0ZEtKaHFxZl9FX1RNY0tIaUwzXzB2YWpGb1BMTlMxVXNnclFXa2RQUTQxd0RnYmZnS0JINGQyT29GamV6VVJPVmJTSHhjV2R1YUVjWmVJRVZDUnB1bHpKTGxnOGd5dGZ3Ty1TcXRoOE1YTkxPRGVhNHdQNzlYLXM3M2ZVZTVvRTFlQ19uUGlpR1diMlpsYmt4Z3MiLCJhbGciOiJSUzI1NiIsImtpZCI6InBvd2Vyc3luYy1iNGUwMTMzN2Q3In0= # ==================== PowerSync variables ==================== # The PowerSync API is accessible via this port diff --git a/dev-postgres-powersync/config-powersync/powersync.yaml b/dev-postgres-powersync/config-powersync/powersync.yaml index 4ff147957..81643bab5 100644 --- a/dev-postgres-powersync/config-powersync/powersync.yaml +++ b/dev-postgres-powersync/config-powersync/powersync.yaml @@ -52,22 +52,11 @@ replication: sslmode: disable # 'verify-full' (default) or 'verify-ca' or 'disable' # 'disable' is OK for local/private networks, not for public networks - # Required for verify-ca, optional for verify-full - # cacert: ${PS_PG_CA_CERT} - - # Include a certificate here for HTTPs - # client_certificate: ${PS_PG_CLIENT_CERT} - # client_private_key: ${PS_PG_CLIENT_PRIVATE_KEY} - -# This is valid if using the `mongo` service defined in `ps-mongo.yaml` # Connection settings for sync bucket storage storage: type: mongodb uri: !env PS_MONGO_URI - # Use these if authentication is required. The user should have `readWrite` and `dbAdmin` roles - # username: my-mongo-user - # password: my-password # The port which the PowerSync API server will listen on port: !env PS_PORT diff --git a/dev-postgres-powersync/config-powersync/sync_rules.yaml b/dev-postgres-powersync/config-powersync/sync_rules.yaml index 6a1cc21f0..17493b20c 100644 --- a/dev-postgres-powersync/config-powersync/sync_rules.yaml +++ b/dev-postgres-powersync/config-powersync/sync_rules.yaml @@ -3,9 +3,13 @@ # Note that changes to this file are not watched. # The service needs to be restarted for changes to take effect. bucket_definitions: - user_lists: - # Separate bucket per todo list - parameters: select id as list_id from lists where owner_id = token_parameters.user_id + global: data: - - select * from lists where id = bucket.list_id - - select * from todos where list_id = bucket.list_id + - select * from exercises_muscle + +# user_lists: +# Separate bucket per todo list +# parameters: select id as list_id from lists where owner_id = token_parameters.user_id +# data: +# - select * from lists where id = bucket.list_id +# - select * from todos where list_id = bucket.list_id diff --git a/dev-postgres-powersync/docker-compose.yml b/dev-postgres-powersync/docker-compose.yml index b8bfd291f..1fb485763 100644 --- a/dev-postgres-powersync/docker-compose.yml +++ b/dev-postgres-powersync/docker-compose.yml @@ -2,7 +2,7 @@ name: wger-dev-postgres-powersync services: web: - image: wger/server:powersync + image: wger/server:latest depends_on: db: condition: service_healthy @@ -14,13 +14,9 @@ services: # From the PowerSync service name # This is just used to populate the JWT audience POWERSYNC_URL: powersync-dev - - # Keys here for demonstration - POWERSYNC_PUBLIC_KEY: ${DEMO_JWKS_PUBLIC_KEY} - POWERSYNC_PRIVATE_KEY: ${DEMO_JWKS_PRIVATE_KEY} volumes: - type: bind - source: /home/dieter/code/wger-wger + source: /Users/roland/Entwicklung/wger/server target: /home/wger/src ports: - "8000:8000" diff --git a/dev-postgres-powersync/powersync-services/powersync.yaml b/dev-postgres-powersync/powersync-services/powersync.yaml index 85212dc5f..03c89bb45 100644 --- a/dev-postgres-powersync/powersync-services/powersync.yaml +++ b/dev-postgres-powersync/powersync-services/powersync.yaml @@ -55,15 +55,6 @@ services: # The port which the PowerSync API server should run on PS_PORT: ${PS_PORT} - # CA certificate for Postgres connection - # PS_PG_CA_CERT: - - # Client certificate for Postgres connection - # PS_PG_CLIENT_CERT: - - # Client private key for Postgres connection - # PS_PG_CLIENT_PRIVATE_KEY: - # Potential JWKs public key template # PS_JWK_N: # PS_JWK_E: From d82403734f02fc374cb5478cf58134db819d3755 Mon Sep 17 00:00:00 2001 From: Roland Geider Date: Sun, 8 Sep 2024 20:52:18 +0200 Subject: [PATCH 03/53] Update JWT powersync keys --- dev-postgres-powersync/.env | 4 ++-- dev-postgres-powersync/config-powersync/powersync.yaml | 10 +--------- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/dev-postgres-powersync/.env b/dev-postgres-powersync/.env index cf902a97f..5a89c2b3f 100644 --- a/dev-postgres-powersync/.env +++ b/dev-postgres-powersync/.env @@ -9,8 +9,8 @@ PS_JWKS_URL=http://web:8000/api/v2/powersync-keys # 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=eyJrdHkiOiJSU0EiLCJuIjoienNsem9lajhpdFZIR3BWRXYySUtqSU5ORmVUZ1R4X0NRcF9lc2Q4S0VrQ3ZjQXMtSXVpNmw5WXQ1VUNKb2Vmemo5Nmp5Z3FxS0JzUFdLSC1hOXlHdnd6NmRZZ1hqWkdlRUozUXc0UWxxYjhoNlotVU1FeXFGWlVUNUN6d0RiTTBkM1BiVEVJTGJhNnRldHhHNlN2cldwVU5HVnBZczN0SXdVaEdEcGd0RnM5UV91YXRhb0dhcUpRa0pXWTJ1SkhqRHFOQVpEVjliazBzYmhYcnI3dnZoeXVaYVRBZngtNWVCZktSd1FWcGtCRzhabWZHbVNGMnVtWmhpVUhNOUhRYW5zN1ZoWS1ISm5CbFpoNjVhMGpkbncwaHFiX0REaDJSRWNfZktmSmg1UkloZ19zQzBrT29hWjZNS29GOXl0QUNsN0FxdXFlNHZBcEJDUG1aV21KVTZ3IiwiZSI6IkFRQUIiLCJhbGciOiJSUzI1NiIsImtpZCI6InBvd2Vyc3luYy1iNGUwMTMzN2Q3In0= -POWERSYNC_JWKS_PRIVATE_KEY=eyJrdHkiOiJSU0EiLCJuIjoienNsem9lajhpdFZIR3BWRXYySUtqSU5ORmVUZ1R4X0NRcF9lc2Q4S0VrQ3ZjQXMtSXVpNmw5WXQ1VUNKb2Vmemo5Nmp5Z3FxS0JzUFdLSC1hOXlHdnd6NmRZZ1hqWkdlRUozUXc0UWxxYjhoNlotVU1FeXFGWlVUNUN6d0RiTTBkM1BiVEVJTGJhNnRldHhHNlN2cldwVU5HVnBZczN0SXdVaEdEcGd0RnM5UV91YXRhb0dhcUpRa0pXWTJ1SkhqRHFOQVpEVjliazBzYmhYcnI3dnZoeXVaYVRBZngtNWVCZktSd1FWcGtCRzhabWZHbVNGMnVtWmhpVUhNOUhRYW5zN1ZoWS1ISm5CbFpoNjVhMGpkbncwaHFiX0REaDJSRWNfZktmSmg1UkloZ19zQzBrT29hWjZNS29GOXl0QUNsN0FxdXFlNHZBcEJDUG1aV21KVTZ3IiwiZSI6IkFRQUIiLCJkIjoiUTJtUEpjaGpsQXNGZkJnUGFtalcwWW40ZGx1Xy1HdDlFLVUwWHo0NzlVbGJLQ2F5SWdWRzF6ci1pVThwenp0anZwSXhTU3VDMzBJN0ZZVHlBVTNLSzd4YVpqaHduVGxNazFRdmU1MjNfWWVPMGEteFNyR2pmUmUxZlZ4ZEFjcGJIMW9Jc3VxUS1UZkozRlMxVlV4NUZIV2s2SV80Zk1LRExHZVlWeWVyQTFVS1NXZUoxYThjeUhLSTVCOUVyNkhKaGVYb1NDTVhYeS1rRFd1em1Sclp3TGVzd0g3SHI4d00wRXdfTUN4MnA3NUU2bU8zZnBlcUZKV1dwSGZqV2ZoVGp0RkVBOHVPMGd6dGdJSzlhbkVSV1FhMEx4b29NZ2E0TDczRFFYMFNyczFZdTQwYlJ2WWZJY3k2ZThFc2M2eFFjYkZtV29mVWlneEZJODZ1bXdIQktRIiwicCI6Ijl2aVNpOE9ueG1nVlVFZW5aLVhoa0haVHh2V2NGZjI5YWVYYVhHVGtMTlBzMHBMRFFZd01lWGFTandaUk5FQngxR2tPQ1I5dEFoV3JRNWxBaW5MeHNxX1JFT2VQajA0QTJ2U2RNQnIybWJuM2lxT0htaE9iQXhPOUd4OHdWNWt4V255YnJkeGE0dkRtdmV6QkJqaEdfYS1XenhMSUZSNUw4Q3dPd1R2UkRNMCIsInEiOiIxbGpLMWh6Nzh1aGYyWHBjNmw4T0FueFRxbnlYQ1pkM3VJQ1hTSW9wMXlXaVlSVWxVZk9EVW1XWG8yVE93RHIzM0Joc091YktBT3FSTm1Gc0ZWaTgzM1JVMjFXeFBOVHRqUllSRzYteHFId0NfYlBFQTAzbExYNkM0aVo3R254aHRpN2JEX0UxRy1OaXBRZFNHOEVwTEFwYnFzTmUzWTA0NUVSbzdaaGk2SmMiLCJkcCI6InZmQ1FyR01PanA0UF9rME5aLS01bWVRWExJWkt3X01CRVFmUTk0dzBuSEZreXRKS3p3ZUp0SVRIMUszVUdDNlVIUHVxNnNNN2tBWGdVTDMxa0VVMHMtdGFDX2s3Uk1pR0NkOWxZTkRyNVhETC05a20tZzJvQXliVUlwN0xEQ1BxZkNBbmp3QlEtZ2F5UDFGdFpuNHp3dm1mTDZUUE1zYTVPbjUzM285RmlPVSIsImRxIjoicmRTU292UWNpOUZTTWxBZTNGLThQOTNPQ0Z4RUxSNHVsRzJNd3VKeHJpNnlNbU53d2JabjBNSGRLVUNPdjZ6UzZDYlNWeTVsc2pxSkMzNFVwbmN4clZKdG92Y3E1cmVUOHpCckxYWGQ4VktwSmxETWJSV1ZfOEF5cXU4a05NV2NoS0FaUGlPU3U0dzdxclIyTFZZSWF0UDNwVlFPTWtUZVY1ajNNNEM2N2Y4IiwicWkiOiJOM3RDNm1RbHZkcVdEVVh1b2MtT1Mteno0ZEtKaHFxZl9FX1RNY0tIaUwzXzB2YWpGb1BMTlMxVXNnclFXa2RQUTQxd0RnYmZnS0JINGQyT29GamV6VVJPVmJTSHhjV2R1YUVjWmVJRVZDUnB1bHpKTGxnOGd5dGZ3Ty1TcXRoOE1YTkxPRGVhNHdQNzlYLXM3M2ZVZTVvRTFlQ19uUGlpR1diMlpsYmt4Z3MiLCJhbGciOiJSUzI1NiIsImtpZCI6InBvd2Vyc3luYy1iNGUwMTMzN2Q3In0= +POWERSYNC_JWKS_PUBLIC_KEY=eyJhbGciOiAiUlMyNTYiLCAia3R5IjogIlJTQSIsICJuIjogInFhdVVnb0ZXenRNcjVEYks3bFIxZXUxazJrdllyblJkRGh1NDFyWnFLeWhDWkJya0FTS0d0N25KbVUwVEpKb1d0cFF2eHVvc0ZGeW1BMUhXQnNaY0dtVlcxdlowdDJlazl4THg5bjg2UWRIVWc1MktsRG9ZUzNtRTFaWW5BYzJfRDM3UmxyQkVxRXpuSnBNeDJ3VkpLcVdRZHlWSWh6Q082YzRnOWN3VExGbUhkVXVURXMzdDNBN1MyNENrUkM2TE1KSFFvRTJzay1uWlJyZE9fTHVNNUJJcVp2b1dWUC1Salp4OWk4OGdaaDhvOEcyWW1xZnMwczRzYW1fam85bmFaYlo4aFBFQ0FZdnZUZ29ObzRHMGpXZERZeGdPWHlXTE80bTk1SEdMSFJMZjZ5M29vdkZad2QwN2FFbThEU3dBX3hsY1V4WHNNZ0ZlYVVVZkp2NEV4USIsICJlIjogIkFRQUIiLCAia2lkIjogInBvd2Vyc3luYyJ9 +POWERSYNC_JWKS_PRIVATE_KEY=eyJhbGciOiAiUlMyNTYiLCAia3R5IjogIlJTQSIsICJuIjogInFhdVVnb0ZXenRNcjVEYks3bFIxZXUxazJrdllyblJkRGh1NDFyWnFLeWhDWkJya0FTS0d0N25KbVUwVEpKb1d0cFF2eHVvc0ZGeW1BMUhXQnNaY0dtVlcxdlowdDJlazl4THg5bjg2UWRIVWc1MktsRG9ZUzNtRTFaWW5BYzJfRDM3UmxyQkVxRXpuSnBNeDJ3VkpLcVdRZHlWSWh6Q082YzRnOWN3VExGbUhkVXVURXMzdDNBN1MyNENrUkM2TE1KSFFvRTJzay1uWlJyZE9fTHVNNUJJcVp2b1dWUC1Salp4OWk4OGdaaDhvOEcyWW1xZnMwczRzYW1fam85bmFaYlo4aFBFQ0FZdnZUZ29ObzRHMGpXZERZeGdPWHlXTE80bTk1SEdMSFJMZjZ5M29vdkZad2QwN2FFbThEU3dBX3hsY1V4WHNNZ0ZlYVVVZkp2NEV4USIsICJlIjogIkFRQUIiLCAiZCI6ICJQZXVwNjhUakZ1RVhaQmFoRWNDT0RWcEUwNndaZkhWb0hvVjhmQk9maEhlUlh6STNJcmprZkhtWHV0UlhsNlNLaElCcFBVbHA0OVo2R2IwTWhIVncySXRDV1hvaFYydkNWdzg1Y2RHMXc1NmQxWml4b2UzZnZ1LXV6RG9icXp0WXJvR0VZTi1jZHVWMS1HeUFwZU4wYzlWdmR5UUtwNWZQbUVGTFl4amlxR3k5UUhyTldpcGJmZXdPUGY0YUl4X05VRnE3R1BsUk1yalA4VEhvSzNPOVNfXzJpR09LRVpINDFUWkpscVBZX0s5dFNkbFNKd1FPWEtwOFc2ZUdGT3l2MElueVhsUXhHb0ZBWVNrUC12WTlWQy1vTUtzdmhocm1GeGM0VlU2OUZ3VWFJYUdaOU9jaXF4M3B0aE9sU1drRjFhbEtxNWFJZ2VHbEUzM2VyNGthSXciLCAicCI6ICI1WDN0QzN4Z0hwbm91U1JwSlg4c0ZWRm5vamhxMWJoWkF3c3VRaXBxWWgtZmJNRGI4a2NTTy1fT3BEMExNekYzcHp0dVNRb0NZOFc0WjI0TEJ6cFRuUlFid0JrYWt3VDMybmZIU1J0d3RnM1ZjWkkxZFNsdHgtclhEcHlBMDNHa1RvLUxEZkp1UzF0a1FYQXB0OTBkcnJHMndjQ25oRXc4bGx2SzR2cWRucHMiLCAicSI6ICJ2VVM2V2QtY2trTUJMVmJvSkVaVnRtMlFLTFE2dV9oZEFrbTFWa3dGajMxZWZWRTlFRWRSa0F0dGVoOWh2ZzBkM2FXVDZ1bFQ4YlpubWo3WkFjNG55aVdwOTlFd0k5U0hFX01UUE11YVZSeUw5SmFIX2R0Uk5nVGE5UV9hZUs2d1pkY3RwLUZRT1lteVlDWmhzRnVOTG45TFJ3UklJOVJ0YlBXYW55X01jQjgiLCAiZHAiOiAiWjFNNkhmakN3aVJqcnJBaEV6dmQyajlMbkxNd0RzZXdjX2xkdTNhamJVaDFuQjU5S09rczRZV0lFVlJXclpieEczOWJtVkVEWUc2T0p5dFpsY2lDQ3ZBWnluVEREVHlvWjFtVWhXcndaVmQzS1dvOTNXRm94eUVKOE04d0JZTmVDZTBCRzZkeVYwVnZyekxUNWEtTmhMRUk2dFZWMXZBSU8xNWF5N1V3c0U4IiwgImRxIjogIktsclpBUWZEZUEtNmtiVGpHa3NMSDFvQmFycDZjbG93SmpUc2ViVmxnU2pqSGxReHdCVFZzZEI4M1Zsc2ZDVmZTNXlrTDJ1cnQybkVZWVl5OWU1MmhReE1yd0tITFYyQUpQeS1qMXBZM1RjWU10SUUtTkE5cWtNSDVOTjVab3hoT1VrZ0ZIT2RpbUxBSWpnMG9FeThtVzB2SVdOWjZYcS1TaVhrUmo5aUZxMCIsICJxaSI6ICJzSV84RTh0MTBsRDY2NTh3UXRpY19BaUUxOVk1Rms0SDJWbnpGclBhVU04aWFNaVc2eUZxMFZuN3RXa2RTWS1STTB1SFMwdmVmSEcyZTBKSWxEanhBUmZWZUcwNTFyVUNRZjBkSnR4U0ZDQUp2eGxMRTZsYjZOQlUwZVIyMld6bjVob1ZZTVpHZnQ5QnA0SlVOOHJkMF9lMm1kSjhxc09wM1NLQ3NTSTByUkkiLCAia2lkIjogInBvd2Vyc3luYyJ9 # ==================== PowerSync variables ==================== # The PowerSync API is accessible via this port diff --git a/dev-postgres-powersync/config-powersync/powersync.yaml b/dev-postgres-powersync/config-powersync/powersync.yaml index 81643bab5..7b0008c6c 100644 --- a/dev-postgres-powersync/config-powersync/powersync.yaml +++ b/dev-postgres-powersync/config-powersync/powersync.yaml @@ -69,18 +69,10 @@ sync_rules: 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 - # Optional static collection of public keys for JWT verification - # jwks: - # keys: - # - kty: 'RSA' - # n: '${PS_JWK_N}' - # e: '${PS_JWK_E}' - # alg: 'RS256' - # kid: '${PS_JWK_KID}' - # JWKS audience audience: ["powersync-dev", "powersync"] From ff6216318f3fc5428a657316f58a671482c4b89b Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Fri, 2 Aug 2024 22:59:22 +0300 Subject: [PATCH 04/53] add more startup options --- config/dev.env | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/config/dev.env b/config/dev.env index 0cad32601..7f70db32a 100644 --- a/config/dev.env +++ b/config/dev.env @@ -1,5 +1,12 @@ 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=True # a couple of ingredients +SYNC_INGREDIENTS_ON_STARTUP=False # lots of ingredients. expensive AXES_ENABLED=False + + From aa16ad81fe73e9d47ccbea440f072a8d72d97c16 Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Mon, 16 Sep 2024 12:38:38 +0300 Subject: [PATCH 05/53] fixes/tweaks --- config/dev.env | 2 ++ dev-postgres-powersync/.env | 1 + .../config-powersync/sync_rules.yaml | 21 ++++++++++++------- dev-postgres-powersync/docker-compose.yml | 2 +- .../powersync-services/powersync.yaml | 2 +- 5 files changed, 19 insertions(+), 9 deletions(-) diff --git a/config/dev.env b/config/dev.env index 7f70db32a..a79869ce0 100644 --- a/config/dev.env +++ b/config/dev.env @@ -9,4 +9,6 @@ LOAD_ONLINE_FIXTURES_ON_STARTUP=True # a couple of ingredients SYNC_INGREDIENTS_ON_STARTUP=False # lots of ingredients. expensive AXES_ENABLED=False +POWERSYNC_JWKS_PUBLIC_KEY=eyJhbGciOiAiUlMyNTYiLCAia3R5IjogIlJTQSIsICJuIjogInFhdVVnb0ZXenRNcjVEYks3bFIxZXUxazJrdllyblJkRGh1NDFyWnFLeWhDWkJya0FTS0d0N25KbVUwVEpKb1d0cFF2eHVvc0ZGeW1BMUhXQnNaY0dtVlcxdlowdDJlazl4THg5bjg2UWRIVWc1MktsRG9ZUzNtRTFaWW5BYzJfRDM3UmxyQkVxRXpuSnBNeDJ3VkpLcVdRZHlWSWh6Q082YzRnOWN3VExGbUhkVXVURXMzdDNBN1MyNENrUkM2TE1KSFFvRTJzay1uWlJyZE9fTHVNNUJJcVp2b1dWUC1Salp4OWk4OGdaaDhvOEcyWW1xZnMwczRzYW1fam85bmFaYlo4aFBFQ0FZdnZUZ29ObzRHMGpXZERZeGdPWHlXTE80bTk1SEdMSFJMZjZ5M29vdkZad2QwN2FFbThEU3dBX3hsY1V4WHNNZ0ZlYVVVZkp2NEV4USIsICJlIjogIkFRQUIiLCAia2lkIjogInBvd2Vyc3luYyJ9 +POWERSYNC_JWKS_PRIVATE_KEY=eyJhbGciOiAiUlMyNTYiLCAia3R5IjogIlJTQSIsICJuIjogInFhdVVnb0ZXenRNcjVEYks3bFIxZXUxazJrdllyblJkRGh1NDFyWnFLeWhDWkJya0FTS0d0N25KbVUwVEpKb1d0cFF2eHVvc0ZGeW1BMUhXQnNaY0dtVlcxdlowdDJlazl4THg5bjg2UWRIVWc1MktsRG9ZUzNtRTFaWW5BYzJfRDM3UmxyQkVxRXpuSnBNeDJ3VkpLcVdRZHlWSWh6Q082YzRnOWN3VExGbUhkVXVURXMzdDNBN1MyNENrUkM2TE1KSFFvRTJzay1uWlJyZE9fTHVNNUJJcVp2b1dWUC1Salp4OWk4OGdaaDhvOEcyWW1xZnMwczRzYW1fam85bmFaYlo4aFBFQ0FZdnZUZ29ObzRHMGpXZERZeGdPWHlXTE80bTk1SEdMSFJMZjZ5M29vdkZad2QwN2FFbThEU3dBX3hsY1V4WHNNZ0ZlYVVVZkp2NEV4USIsICJlIjogIkFRQUIiLCAiZCI6ICJQZXVwNjhUakZ1RVhaQmFoRWNDT0RWcEUwNndaZkhWb0hvVjhmQk9maEhlUlh6STNJcmprZkhtWHV0UlhsNlNLaElCcFBVbHA0OVo2R2IwTWhIVncySXRDV1hvaFYydkNWdzg1Y2RHMXc1NmQxWml4b2UzZnZ1LXV6RG9icXp0WXJvR0VZTi1jZHVWMS1HeUFwZU4wYzlWdmR5UUtwNWZQbUVGTFl4amlxR3k5UUhyTldpcGJmZXdPUGY0YUl4X05VRnE3R1BsUk1yalA4VEhvSzNPOVNfXzJpR09LRVpINDFUWkpscVBZX0s5dFNkbFNKd1FPWEtwOFc2ZUdGT3l2MElueVhsUXhHb0ZBWVNrUC12WTlWQy1vTUtzdmhocm1GeGM0VlU2OUZ3VWFJYUdaOU9jaXF4M3B0aE9sU1drRjFhbEtxNWFJZ2VHbEUzM2VyNGthSXciLCAicCI6ICI1WDN0QzN4Z0hwbm91U1JwSlg4c0ZWRm5vamhxMWJoWkF3c3VRaXBxWWgtZmJNRGI4a2NTTy1fT3BEMExNekYzcHp0dVNRb0NZOFc0WjI0TEJ6cFRuUlFid0JrYWt3VDMybmZIU1J0d3RnM1ZjWkkxZFNsdHgtclhEcHlBMDNHa1RvLUxEZkp1UzF0a1FYQXB0OTBkcnJHMndjQ25oRXc4bGx2SzR2cWRucHMiLCAicSI6ICJ2VVM2V2QtY2trTUJMVmJvSkVaVnRtMlFLTFE2dV9oZEFrbTFWa3dGajMxZWZWRTlFRWRSa0F0dGVoOWh2ZzBkM2FXVDZ1bFQ4YlpubWo3WkFjNG55aVdwOTlFd0k5U0hFX01UUE11YVZSeUw5SmFIX2R0Uk5nVGE5UV9hZUs2d1pkY3RwLUZRT1lteVlDWmhzRnVOTG45TFJ3UklJOVJ0YlBXYW55X01jQjgiLCAiZHAiOiAiWjFNNkhmakN3aVJqcnJBaEV6dmQyajlMbkxNd0RzZXdjX2xkdTNhamJVaDFuQjU5S09rczRZV0lFVlJXclpieEczOWJtVkVEWUc2T0p5dFpsY2lDQ3ZBWnluVEREVHlvWjFtVWhXcndaVmQzS1dvOTNXRm94eUVKOE04d0JZTmVDZTBCRzZkeVYwVnZyekxUNWEtTmhMRUk2dFZWMXZBSU8xNWF5N1V3c0U4IiwgImRxIjogIktsclpBUWZEZUEtNmtiVGpHa3NMSDFvQmFycDZjbG93SmpUc2ViVmxnU2pqSGxReHdCVFZzZEI4M1Zsc2ZDVmZTNXlrTDJ1cnQybkVZWVl5OWU1MmhReE1yd0tITFYyQUpQeS1qMXBZM1RjWU10SUUtTkE5cWtNSDVOTjVab3hoT1VrZ0ZIT2RpbUxBSWpnMG9FeThtVzB2SVdOWjZYcS1TaVhrUmo5aUZxMCIsICJxaSI6ICJzSV84RTh0MTBsRDY2NTh3UXRpY19BaUUxOVk1Rms0SDJWbnpGclBhVU04aWFNaVc2eUZxMFZuN3RXa2RTWS1STTB1SFMwdmVmSEcyZTBKSWxEanhBUmZWZUcwNTFyVUNRZjBkSnR4U0ZDQUp2eGxMRTZsYjZOQlUwZVIyMld6bjVob1ZZTVpHZnQ5QnA0SlVOOHJkMF9lMm1kSjhxc09wM1NLQ3NTSTByUkkiLCAia2lkIjogInBvd2Vyc3luYyJ9 diff --git a/dev-postgres-powersync/.env b/dev-postgres-powersync/.env index 5a89c2b3f..2b895037a 100644 --- a/dev-postgres-powersync/.env +++ b/dev-postgres-powersync/.env @@ -9,6 +9,7 @@ PS_JWKS_URL=http://web:8000/api/v2/powersync-keys # 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 +# TODO: do we need these here? at least django needs them POWERSYNC_JWKS_PUBLIC_KEY=eyJhbGciOiAiUlMyNTYiLCAia3R5IjogIlJTQSIsICJuIjogInFhdVVnb0ZXenRNcjVEYks3bFIxZXUxazJrdllyblJkRGh1NDFyWnFLeWhDWkJya0FTS0d0N25KbVUwVEpKb1d0cFF2eHVvc0ZGeW1BMUhXQnNaY0dtVlcxdlowdDJlazl4THg5bjg2UWRIVWc1MktsRG9ZUzNtRTFaWW5BYzJfRDM3UmxyQkVxRXpuSnBNeDJ3VkpLcVdRZHlWSWh6Q082YzRnOWN3VExGbUhkVXVURXMzdDNBN1MyNENrUkM2TE1KSFFvRTJzay1uWlJyZE9fTHVNNUJJcVp2b1dWUC1Salp4OWk4OGdaaDhvOEcyWW1xZnMwczRzYW1fam85bmFaYlo4aFBFQ0FZdnZUZ29ObzRHMGpXZERZeGdPWHlXTE80bTk1SEdMSFJMZjZ5M29vdkZad2QwN2FFbThEU3dBX3hsY1V4WHNNZ0ZlYVVVZkp2NEV4USIsICJlIjogIkFRQUIiLCAia2lkIjogInBvd2Vyc3luYyJ9 POWERSYNC_JWKS_PRIVATE_KEY=eyJhbGciOiAiUlMyNTYiLCAia3R5IjogIlJTQSIsICJuIjogInFhdVVnb0ZXenRNcjVEYks3bFIxZXUxazJrdllyblJkRGh1NDFyWnFLeWhDWkJya0FTS0d0N25KbVUwVEpKb1d0cFF2eHVvc0ZGeW1BMUhXQnNaY0dtVlcxdlowdDJlazl4THg5bjg2UWRIVWc1MktsRG9ZUzNtRTFaWW5BYzJfRDM3UmxyQkVxRXpuSnBNeDJ3VkpLcVdRZHlWSWh6Q082YzRnOWN3VExGbUhkVXVURXMzdDNBN1MyNENrUkM2TE1KSFFvRTJzay1uWlJyZE9fTHVNNUJJcVp2b1dWUC1Salp4OWk4OGdaaDhvOEcyWW1xZnMwczRzYW1fam85bmFaYlo4aFBFQ0FZdnZUZ29ObzRHMGpXZERZeGdPWHlXTE80bTk1SEdMSFJMZjZ5M29vdkZad2QwN2FFbThEU3dBX3hsY1V4WHNNZ0ZlYVVVZkp2NEV4USIsICJlIjogIkFRQUIiLCAiZCI6ICJQZXVwNjhUakZ1RVhaQmFoRWNDT0RWcEUwNndaZkhWb0hvVjhmQk9maEhlUlh6STNJcmprZkhtWHV0UlhsNlNLaElCcFBVbHA0OVo2R2IwTWhIVncySXRDV1hvaFYydkNWdzg1Y2RHMXc1NmQxWml4b2UzZnZ1LXV6RG9icXp0WXJvR0VZTi1jZHVWMS1HeUFwZU4wYzlWdmR5UUtwNWZQbUVGTFl4amlxR3k5UUhyTldpcGJmZXdPUGY0YUl4X05VRnE3R1BsUk1yalA4VEhvSzNPOVNfXzJpR09LRVpINDFUWkpscVBZX0s5dFNkbFNKd1FPWEtwOFc2ZUdGT3l2MElueVhsUXhHb0ZBWVNrUC12WTlWQy1vTUtzdmhocm1GeGM0VlU2OUZ3VWFJYUdaOU9jaXF4M3B0aE9sU1drRjFhbEtxNWFJZ2VHbEUzM2VyNGthSXciLCAicCI6ICI1WDN0QzN4Z0hwbm91U1JwSlg4c0ZWRm5vamhxMWJoWkF3c3VRaXBxWWgtZmJNRGI4a2NTTy1fT3BEMExNekYzcHp0dVNRb0NZOFc0WjI0TEJ6cFRuUlFid0JrYWt3VDMybmZIU1J0d3RnM1ZjWkkxZFNsdHgtclhEcHlBMDNHa1RvLUxEZkp1UzF0a1FYQXB0OTBkcnJHMndjQ25oRXc4bGx2SzR2cWRucHMiLCAicSI6ICJ2VVM2V2QtY2trTUJMVmJvSkVaVnRtMlFLTFE2dV9oZEFrbTFWa3dGajMxZWZWRTlFRWRSa0F0dGVoOWh2ZzBkM2FXVDZ1bFQ4YlpubWo3WkFjNG55aVdwOTlFd0k5U0hFX01UUE11YVZSeUw5SmFIX2R0Uk5nVGE5UV9hZUs2d1pkY3RwLUZRT1lteVlDWmhzRnVOTG45TFJ3UklJOVJ0YlBXYW55X01jQjgiLCAiZHAiOiAiWjFNNkhmakN3aVJqcnJBaEV6dmQyajlMbkxNd0RzZXdjX2xkdTNhamJVaDFuQjU5S09rczRZV0lFVlJXclpieEczOWJtVkVEWUc2T0p5dFpsY2lDQ3ZBWnluVEREVHlvWjFtVWhXcndaVmQzS1dvOTNXRm94eUVKOE04d0JZTmVDZTBCRzZkeVYwVnZyekxUNWEtTmhMRUk2dFZWMXZBSU8xNWF5N1V3c0U4IiwgImRxIjogIktsclpBUWZEZUEtNmtiVGpHa3NMSDFvQmFycDZjbG93SmpUc2ViVmxnU2pqSGxReHdCVFZzZEI4M1Zsc2ZDVmZTNXlrTDJ1cnQybkVZWVl5OWU1MmhReE1yd0tITFYyQUpQeS1qMXBZM1RjWU10SUUtTkE5cWtNSDVOTjVab3hoT1VrZ0ZIT2RpbUxBSWpnMG9FeThtVzB2SVdOWjZYcS1TaVhrUmo5aUZxMCIsICJxaSI6ICJzSV84RTh0MTBsRDY2NTh3UXRpY19BaUUxOVk1Rms0SDJWbnpGclBhVU04aWFNaVc2eUZxMFZuN3RXa2RTWS1STTB1SFMwdmVmSEcyZTBKSWxEanhBUmZWZUcwNTFyVUNRZjBkSnR4U0ZDQUp2eGxMRTZsYjZOQlUwZVIyMld6bjVob1ZZTVpHZnQ5QnA0SlVOOHJkMF9lMm1kSjhxc09wM1NLQ3NTSTByUkkiLCAia2lkIjogInBvd2Vyc3luYyJ9 diff --git a/dev-postgres-powersync/config-powersync/sync_rules.yaml b/dev-postgres-powersync/config-powersync/sync_rules.yaml index 17493b20c..79beaca1d 100644 --- a/dev-postgres-powersync/config-powersync/sync_rules.yaml +++ b/dev-postgres-powersync/config-powersync/sync_rules.yaml @@ -6,10 +6,17 @@ bucket_definitions: global: data: - select * from exercises_muscle - -# user_lists: -# Separate bucket per todo list -# parameters: select id as list_id from lists where owner_id = token_parameters.user_id -# data: -# - select * from lists where id = bucket.list_id -# - select * from todos where list_id = bucket.list_id + nutrition_plan: + parameters: SELECT token_parameters.user_id as user_id + data: + - select * from nutrition_nutritionplan where user_id = bucket.user_id + by_plan_table: + parameters: SELECT id as plan_id FROM nutrition_nutritionplan WHERE user_id = token_parameters.user_id + data: + - SELECT * FROM nutrition_meal WHERE nutrition_meal.plan_id = bucket.plan_id + - select * from nutrition_logitem WHERE nutrition_logitem.plan_id = bucket.plan_id + # ingredient 1<->N log N-1 plan N-1 user + # post N-1 board N-1 user + # also + # mealItem has a meal_id and ingredient_id + # diff --git a/dev-postgres-powersync/docker-compose.yml b/dev-postgres-powersync/docker-compose.yml index 1fb485763..e5590c4d9 100644 --- a/dev-postgres-powersync/docker-compose.yml +++ b/dev-postgres-powersync/docker-compose.yml @@ -16,7 +16,7 @@ services: POWERSYNC_URL: powersync-dev volumes: - type: bind - source: /Users/roland/Entwicklung/wger/server + source: ${WGER_CODEPATH} target: /home/wger/src ports: - "8000:8000" diff --git a/dev-postgres-powersync/powersync-services/powersync.yaml b/dev-postgres-powersync/powersync-services/powersync.yaml index 03c89bb45..c2369b55c 100644 --- a/dev-postgres-powersync/powersync-services/powersync.yaml +++ b/dev-postgres-powersync/powersync-services/powersync.yaml @@ -47,7 +47,7 @@ services: # The following will be inserted into the powersync.yaml file via templating # Templates are used for filesystem and base64 configuration files PS_PG_URI: postgres://${PG_DATABASE_USER}:${PG_DATABASE_PASSWORD}@db:${PG_DATABASE_PORT}/${PG_DATABASE_NAME} - PS_MONGO_URI: mongodb://mongo:27017/powersync_demo + PS_MONGO_URI: mongodb://mongo:27017/powersync_wger # Note that powersync.yaml->client_auth->allow_local_jwks must be true for local URLs to work PS_JWKS_URL: ${PS_JWKS_URL} From 0768da6ac223e7d6b75868223efd21eacc626df5 Mon Sep 17 00:00:00 2001 From: Roland Geider Date: Wed, 25 Sep 2024 18:39:38 +0200 Subject: [PATCH 06/53] Build pg_ivm postgres extension to be used with powersync --- dev-postgres-powersync/docker-compose.yml | 13 +++++++++--- postgres/Dockerfile | 24 +++++++++++++++++++++++ 2 files changed, 34 insertions(+), 3 deletions(-) create mode 100644 postgres/Dockerfile diff --git a/dev-postgres-powersync/docker-compose.yml b/dev-postgres-powersync/docker-compose.yml index e5590c4d9..b6a7f3e7d 100644 --- a/dev-postgres-powersync/docker-compose.yml +++ b/dev-postgres-powersync/docker-compose.yml @@ -34,17 +34,20 @@ services: restart: unless-stopped db: - image: postgres:15-alpine + build: + context: ../postgres + dockerfile: Dockerfile environment: - POSTGRES_USER=wger - POSTGRES_PASSWORD=wger - POSTGRES_DB=wger volumes: - - postgres-data:/var/lib/postgresql/data/ + - postgres-dev-data:/var/lib/postgresql/data/ 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 @@ -55,7 +58,11 @@ services: restart: unless-stopped volumes: - postgres-data: + postgres-dev-data: + +networks: + default: + name: wger-dev-network include: - path: powersync-services/mongo.yaml diff --git a/postgres/Dockerfile b/postgres/Dockerfile new file mode 100644 index 000000000..013057b65 --- /dev/null +++ b/postgres/Dockerfile @@ -0,0 +1,24 @@ +FROM postgres:15-bookworm AS builder + +ENV VERSION=1.9 + +RUN apt-get update && \ + apt-get install -y \ + git \ + build-essential \ + postgresql-server-dev-15 + +WORKDIR /tmp +RUN git clone -b v${VERSION} https://github.com/sraoss/pg_ivm.git + +WORKDIR /tmp/pg_ivm +RUN make + +# Create the final image +FROM postgres:15-bookworm + +COPY --from=builder /tmp/pg_ivm/pg_ivm*.sql /usr/share/postgresql/15/extension +COPY --from=builder /tmp/pg_ivm/pg_ivm.control /usr/share/postgresql/15/extension +COPY --from=builder /tmp/pg_ivm/pg_ivm.so /usr/lib/postgresql/15/lib + +EXPOSE 5432 \ No newline at end of file From 8af9a6860ec19fe621ec2e1d77f6a4d4b26a40f1 Mon Sep 17 00:00:00 2001 From: Roland Geider Date: Thu, 26 Sep 2024 10:30:55 +0200 Subject: [PATCH 07/53] Simplify powersync docker-compose.yml file Now the .env file only has local configurations like the path to the wger backend checkout --- .gitignore | 1 + config/dev.env | 4 +++- config/prod.env | 9 ++++++++- dev-postgres-powersync/.env | 18 ----------------- dev-postgres-powersync/.env.example | 3 +++ dev-postgres-powersync/docker-compose.yml | 7 +------ .../powersync-services/powersync.yaml | 20 +++++-------------- 7 files changed, 21 insertions(+), 41 deletions(-) delete mode 100644 dev-postgres-powersync/.env create mode 100644 dev-postgres-powersync/.env.example diff --git a/.gitignore b/.gitignore index c949afd4c..ab9062ed4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ /config/Caddyfile /docker-compose.override.yml +/dev-postgres-powersync/.env diff --git a/config/dev.env b/config/dev.env index a79869ce0..5a31537d7 100644 --- a/config/dev.env +++ b/config/dev.env @@ -9,6 +9,8 @@ LOAD_ONLINE_FIXTURES_ON_STARTUP=True # a couple of ingredients SYNC_INGREDIENTS_ON_STARTUP=False # lots of ingredients. expensive AXES_ENABLED=False +# 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 - diff --git a/config/prod.env b/config/prod.env index 276f7b90d..01b047b12 100644 --- a/config/prod.env +++ b/config/prod.env @@ -92,6 +92,9 @@ DJANGO_DB_HOST=db DJANGO_DB_PORT=5432 DJANGO_PERFORM_MIGRATIONS=True # Perform any new database migrations on startup +# postgres://:@:/ +PS_PG_URI=postgres://wger:wger@db:5432/wger + # # Cache DJANGO_CACHE_BACKEND=django_redis.cache.RedisCache @@ -151,4 +154,8 @@ FROM_EMAIL='wger Workout Manager ' # Set your name and email to be notified if an internal server error occurs. # Needs a working email configuration -# DJANGO_ADMINS=your name,email@example.com \ No newline at end of file +# DJANGO_ADMINS=your name,email@example.com + +# +# Powersync +PS_PORT=8080 \ No newline at end of file diff --git a/dev-postgres-powersync/.env b/dev-postgres-powersync/.env deleted file mode 100644 index 2b895037a..000000000 --- a/dev-postgres-powersync/.env +++ /dev/null @@ -1,18 +0,0 @@ -# ==================== Postgres credentials ================================ -PG_DATABASE_NAME=wger -PG_DATABASE_PORT=5432 -PG_DATABASE_USER=wger -PG_DATABASE_PASSWORD=wger - -PS_JWKS_URL=http://web:8000/api/v2/powersync-keys - -# 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 -# TODO: do we need these here? at least django needs them -POWERSYNC_JWKS_PUBLIC_KEY=eyJhbGciOiAiUlMyNTYiLCAia3R5IjogIlJTQSIsICJuIjogInFhdVVnb0ZXenRNcjVEYks3bFIxZXUxazJrdllyblJkRGh1NDFyWnFLeWhDWkJya0FTS0d0N25KbVUwVEpKb1d0cFF2eHVvc0ZGeW1BMUhXQnNaY0dtVlcxdlowdDJlazl4THg5bjg2UWRIVWc1MktsRG9ZUzNtRTFaWW5BYzJfRDM3UmxyQkVxRXpuSnBNeDJ3VkpLcVdRZHlWSWh6Q082YzRnOWN3VExGbUhkVXVURXMzdDNBN1MyNENrUkM2TE1KSFFvRTJzay1uWlJyZE9fTHVNNUJJcVp2b1dWUC1Salp4OWk4OGdaaDhvOEcyWW1xZnMwczRzYW1fam85bmFaYlo4aFBFQ0FZdnZUZ29ObzRHMGpXZERZeGdPWHlXTE80bTk1SEdMSFJMZjZ5M29vdkZad2QwN2FFbThEU3dBX3hsY1V4WHNNZ0ZlYVVVZkp2NEV4USIsICJlIjogIkFRQUIiLCAia2lkIjogInBvd2Vyc3luYyJ9 -POWERSYNC_JWKS_PRIVATE_KEY=eyJhbGciOiAiUlMyNTYiLCAia3R5IjogIlJTQSIsICJuIjogInFhdVVnb0ZXenRNcjVEYks3bFIxZXUxazJrdllyblJkRGh1NDFyWnFLeWhDWkJya0FTS0d0N25KbVUwVEpKb1d0cFF2eHVvc0ZGeW1BMUhXQnNaY0dtVlcxdlowdDJlazl4THg5bjg2UWRIVWc1MktsRG9ZUzNtRTFaWW5BYzJfRDM3UmxyQkVxRXpuSnBNeDJ3VkpLcVdRZHlWSWh6Q082YzRnOWN3VExGbUhkVXVURXMzdDNBN1MyNENrUkM2TE1KSFFvRTJzay1uWlJyZE9fTHVNNUJJcVp2b1dWUC1Salp4OWk4OGdaaDhvOEcyWW1xZnMwczRzYW1fam85bmFaYlo4aFBFQ0FZdnZUZ29ObzRHMGpXZERZeGdPWHlXTE80bTk1SEdMSFJMZjZ5M29vdkZad2QwN2FFbThEU3dBX3hsY1V4WHNNZ0ZlYVVVZkp2NEV4USIsICJlIjogIkFRQUIiLCAiZCI6ICJQZXVwNjhUakZ1RVhaQmFoRWNDT0RWcEUwNndaZkhWb0hvVjhmQk9maEhlUlh6STNJcmprZkhtWHV0UlhsNlNLaElCcFBVbHA0OVo2R2IwTWhIVncySXRDV1hvaFYydkNWdzg1Y2RHMXc1NmQxWml4b2UzZnZ1LXV6RG9icXp0WXJvR0VZTi1jZHVWMS1HeUFwZU4wYzlWdmR5UUtwNWZQbUVGTFl4amlxR3k5UUhyTldpcGJmZXdPUGY0YUl4X05VRnE3R1BsUk1yalA4VEhvSzNPOVNfXzJpR09LRVpINDFUWkpscVBZX0s5dFNkbFNKd1FPWEtwOFc2ZUdGT3l2MElueVhsUXhHb0ZBWVNrUC12WTlWQy1vTUtzdmhocm1GeGM0VlU2OUZ3VWFJYUdaOU9jaXF4M3B0aE9sU1drRjFhbEtxNWFJZ2VHbEUzM2VyNGthSXciLCAicCI6ICI1WDN0QzN4Z0hwbm91U1JwSlg4c0ZWRm5vamhxMWJoWkF3c3VRaXBxWWgtZmJNRGI4a2NTTy1fT3BEMExNekYzcHp0dVNRb0NZOFc0WjI0TEJ6cFRuUlFid0JrYWt3VDMybmZIU1J0d3RnM1ZjWkkxZFNsdHgtclhEcHlBMDNHa1RvLUxEZkp1UzF0a1FYQXB0OTBkcnJHMndjQ25oRXc4bGx2SzR2cWRucHMiLCAicSI6ICJ2VVM2V2QtY2trTUJMVmJvSkVaVnRtMlFLTFE2dV9oZEFrbTFWa3dGajMxZWZWRTlFRWRSa0F0dGVoOWh2ZzBkM2FXVDZ1bFQ4YlpubWo3WkFjNG55aVdwOTlFd0k5U0hFX01UUE11YVZSeUw5SmFIX2R0Uk5nVGE5UV9hZUs2d1pkY3RwLUZRT1lteVlDWmhzRnVOTG45TFJ3UklJOVJ0YlBXYW55X01jQjgiLCAiZHAiOiAiWjFNNkhmakN3aVJqcnJBaEV6dmQyajlMbkxNd0RzZXdjX2xkdTNhamJVaDFuQjU5S09rczRZV0lFVlJXclpieEczOWJtVkVEWUc2T0p5dFpsY2lDQ3ZBWnluVEREVHlvWjFtVWhXcndaVmQzS1dvOTNXRm94eUVKOE04d0JZTmVDZTBCRzZkeVYwVnZyekxUNWEtTmhMRUk2dFZWMXZBSU8xNWF5N1V3c0U4IiwgImRxIjogIktsclpBUWZEZUEtNmtiVGpHa3NMSDFvQmFycDZjbG93SmpUc2ViVmxnU2pqSGxReHdCVFZzZEI4M1Zsc2ZDVmZTNXlrTDJ1cnQybkVZWVl5OWU1MmhReE1yd0tITFYyQUpQeS1qMXBZM1RjWU10SUUtTkE5cWtNSDVOTjVab3hoT1VrZ0ZIT2RpbUxBSWpnMG9FeThtVzB2SVdOWjZYcS1TaVhrUmo5aUZxMCIsICJxaSI6ICJzSV84RTh0MTBsRDY2NTh3UXRpY19BaUUxOVk1Rms0SDJWbnpGclBhVU04aWFNaVc2eUZxMFZuN3RXa2RTWS1STTB1SFMwdmVmSEcyZTBKSWxEanhBUmZWZUcwNTFyVUNRZjBkSnR4U0ZDQUp2eGxMRTZsYjZOQlUwZVIyMld6bjVob1ZZTVpHZnQ5QnA0SlVOOHJkMF9lMm1kSjhxc09wM1NLQ3NTSTByUkkiLCAia2lkIjogInBvd2Vyc3luYyJ9 - -# ==================== PowerSync variables ==================== -# The PowerSync API is accessible via this port -PS_PORT=8080 diff --git a/dev-postgres-powersync/.env.example b/dev-postgres-powersync/.env.example new file mode 100644 index 000000000..a814d23f2 --- /dev/null +++ b/dev-postgres-powersync/.env.example @@ -0,0 +1,3 @@ +# Copy to .env + +WGER_CODEPATH=/path/to/wger/server \ No newline at end of file diff --git a/dev-postgres-powersync/docker-compose.yml b/dev-postgres-powersync/docker-compose.yml index b6a7f3e7d..6ec9b674a 100644 --- a/dev-postgres-powersync/docker-compose.yml +++ b/dev-postgres-powersync/docker-compose.yml @@ -9,14 +9,9 @@ services: env_file: - ../config/prod.env - ../config/dev.env - # django backend should do some powersync stuff.. - environment: - # From the PowerSync service name - # This is just used to populate the JWT audience - POWERSYNC_URL: powersync-dev volumes: - type: bind - source: ${WGER_CODEPATH} + source: ${WGER_CODEPATH:?set the absolute path to the wger backend code in the .env file or env variable} target: /home/wger/src ports: - "8000:8000" diff --git a/dev-postgres-powersync/powersync-services/powersync.yaml b/dev-postgres-powersync/powersync-services/powersync.yaml index c2369b55c..3f9570068 100644 --- a/dev-postgres-powersync/powersync-services/powersync.yaml +++ b/dev-postgres-powersync/powersync-services/powersync.yaml @@ -25,6 +25,9 @@ services: # Mounts the specified config folder to the container # This folder should contain `powersync.yaml and sync_rules.yaml - ../config-powersync:/config + env_file: + - ../../config/prod.env + - ../../config/dev.env environment: # This is the path (inside the container) to the YAML config file # Alternatively the config path can be specified in the command @@ -44,21 +47,8 @@ services: # or e.g.: Via a command line parameter # command: ['start', '-r', 'unified', '-sync64', '[base64 encoded content]'] - # The following will be inserted into the powersync.yaml file via templating - # Templates are used for filesystem and base64 configuration files - PS_PG_URI: postgres://${PG_DATABASE_USER}:${PG_DATABASE_PASSWORD}@db:${PG_DATABASE_PORT}/${PG_DATABASE_NAME} PS_MONGO_URI: mongodb://mongo:27017/powersync_wger - - # Note that powersync.yaml->client_auth->allow_local_jwks must be true for local URLs to work - PS_JWKS_URL: ${PS_JWKS_URL} - - # The port which the PowerSync API server should run on - PS_PORT: ${PS_PORT} - - # Potential JWKs public key template - # PS_JWK_N: - # PS_JWK_E: - # PS_JWK_KID: + PS_JWKS_URL: http://web:8000/api/v2/powersync-keys ports: - - ${PS_PORT}:${PS_PORT} + - 8080:8080 From da8b0a7ea0e1c9e8dfea07894bce4a523a623ff0 Mon Sep 17 00:00:00 2001 From: Roland Geider Date: Wed, 16 Oct 2024 09:14:57 +0200 Subject: [PATCH 08/53] Add dockerfile for development --- dev-postgres-powersync/docker-compose.yml | 3 ++- dev/.env.example | 3 +++ dev/docker-compose.yml | 5 +++-- dev/server.dev.Dockerfile | 21 +++++++++++++++++++++ 4 files changed, 29 insertions(+), 3 deletions(-) create mode 100644 dev/.env.example create mode 100644 dev/server.dev.Dockerfile diff --git a/dev-postgres-powersync/docker-compose.yml b/dev-postgres-powersync/docker-compose.yml index 6ec9b674a..984605fe5 100644 --- a/dev-postgres-powersync/docker-compose.yml +++ b/dev-postgres-powersync/docker-compose.yml @@ -2,7 +2,8 @@ name: wger-dev-postgres-powersync services: web: - image: wger/server:latest + build: + dockerfile: ../dev/server.dev.Dockerfile depends_on: db: condition: service_healthy diff --git a/dev/.env.example b/dev/.env.example new file mode 100644 index 000000000..a814d23f2 --- /dev/null +++ b/dev/.env.example @@ -0,0 +1,3 @@ +# Copy to .env + +WGER_CODEPATH=/path/to/wger/server \ No newline at end of file diff --git a/dev/docker-compose.yml b/dev/docker-compose.yml index 3f36e9a42..74e7f6e71 100644 --- a/dev/docker-compose.yml +++ b/dev/docker-compose.yml @@ -2,14 +2,15 @@ name: wger-dev services: web: - image: wger/server:latest + build: + dockerfile: server.dev.Dockerfile env_file: - ../config/prod.env - ../config/dev.env - ../config/dev-sqlite.env volumes: - type: bind - source: /home/dieter/code/wger-wger + source: ${WGER_CODEPATH:?set the absolute path to the wger backend code in the .env file or env variable} target: /home/wger/src ports: - "8000:8000" diff --git a/dev/server.dev.Dockerfile b/dev/server.dev.Dockerfile new file mode 100644 index 000000000..450eb018c --- /dev/null +++ b/dev/server.dev.Dockerfile @@ -0,0 +1,21 @@ +# +# Installs some additional packages needed for development +# + +FROM wger/server:latest + +USER root +WORKDIR /home/wger/src +RUN apt-get update && \ + apt-get install -y \ + git \ + vim \ + yarnpkg \ + sassc + +RUN ln -s /usr/bin/yarnpkg /usr/bin/yarn \ + && ln -s /usr/bin/sassc /usr/bin/sass \ + && pip3 install --break-system-packages --user -r requirements.txt \ + && pip3 install --break-system-packages --user -r requirements_dev.txt + +USER wger From 5e4bc42947a8d6e569eb447ef7d88a0bc69c6018 Mon Sep 17 00:00:00 2001 From: Roland Geider Date: Wed, 16 Oct 2024 10:42:17 +0200 Subject: [PATCH 09/53] Move development file to the server repo Building it here was not really possible due to the way docker handles its build context --- dev-postgres-powersync/docker-compose.yml | 4 +++- dev/docker-compose.yml | 4 +++- dev/server.dev.Dockerfile | 21 --------------------- 3 files changed, 6 insertions(+), 23 deletions(-) delete mode 100644 dev/server.dev.Dockerfile diff --git a/dev-postgres-powersync/docker-compose.yml b/dev-postgres-powersync/docker-compose.yml index 984605fe5..a5aff29c4 100644 --- a/dev-postgres-powersync/docker-compose.yml +++ b/dev-postgres-powersync/docker-compose.yml @@ -3,7 +3,9 @@ name: wger-dev-postgres-powersync services: web: build: - dockerfile: ../dev/server.dev.Dockerfile + pull: true + context: ${WGER_CODEPATH} + dockerfile: ./extras/docker/development/Dockerfile depends_on: db: condition: service_healthy diff --git a/dev/docker-compose.yml b/dev/docker-compose.yml index 74e7f6e71..99032ce49 100644 --- a/dev/docker-compose.yml +++ b/dev/docker-compose.yml @@ -3,7 +3,9 @@ name: wger-dev services: web: build: - dockerfile: server.dev.Dockerfile + pull: true + context: ${WGER_CODEPATH} + dockerfile: ./extras/docker/development/Dockerfile env_file: - ../config/prod.env - ../config/dev.env diff --git a/dev/server.dev.Dockerfile b/dev/server.dev.Dockerfile deleted file mode 100644 index 450eb018c..000000000 --- a/dev/server.dev.Dockerfile +++ /dev/null @@ -1,21 +0,0 @@ -# -# Installs some additional packages needed for development -# - -FROM wger/server:latest - -USER root -WORKDIR /home/wger/src -RUN apt-get update && \ - apt-get install -y \ - git \ - vim \ - yarnpkg \ - sassc - -RUN ln -s /usr/bin/yarnpkg /usr/bin/yarn \ - && ln -s /usr/bin/sassc /usr/bin/sass \ - && pip3 install --break-system-packages --user -r requirements.txt \ - && pip3 install --break-system-packages --user -r requirements_dev.txt - -USER wger From 88848c4c68395e4188a8a828fe7996c0a4e7313f Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Sat, 12 Oct 2024 11:10:29 +0300 Subject: [PATCH 10/53] cleanup --- config/prod.env | 3 ++- dev-postgres-powersync/powersync-services/powersync.yaml | 2 -- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/config/prod.env b/config/prod.env index 01b047b12..c4aeff4ec 100644 --- a/config/prod.env +++ b/config/prod.env @@ -92,8 +92,9 @@ DJANGO_DB_HOST=db DJANGO_DB_PORT=5432 DJANGO_PERFORM_MIGRATIONS=True # Perform any new database migrations on startup -# postgres://:@:/ +# postgres://:@:/ PS_PG_URI=postgres://wger:wger@db:5432/wger +PS_MONGO_URI: mongodb://mongo:27017/powersync_wger # # Cache diff --git a/dev-postgres-powersync/powersync-services/powersync.yaml b/dev-postgres-powersync/powersync-services/powersync.yaml index 3f9570068..14096ccce 100644 --- a/dev-postgres-powersync/powersync-services/powersync.yaml +++ b/dev-postgres-powersync/powersync-services/powersync.yaml @@ -46,8 +46,6 @@ services: # POWERSYNC_SYNC_RULES_B64: "[base64 encoded sync rules]" # or e.g.: Via a command line parameter # command: ['start', '-r', 'unified', '-sync64', '[base64 encoded content]'] - - PS_MONGO_URI: mongodb://mongo:27017/powersync_wger PS_JWKS_URL: http://web:8000/api/v2/powersync-keys ports: From 024dc14b475b1ccb55ee28956b78c41bb655c4ab Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Sat, 12 Oct 2024 11:13:36 +0300 Subject: [PATCH 11/53] update sync rules --- .../config-powersync/sync_rules.yaml | 27 +++++++++++-------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/dev-postgres-powersync/config-powersync/sync_rules.yaml b/dev-postgres-powersync/config-powersync/sync_rules.yaml index 79beaca1d..d9ac9239b 100644 --- a/dev-postgres-powersync/config-powersync/sync_rules.yaml +++ b/dev-postgres-powersync/config-powersync/sync_rules.yaml @@ -2,21 +2,26 @@ # 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)! bucket_definitions: global: data: - select * from exercises_muscle - nutrition_plan: + by_user_id: parameters: SELECT token_parameters.user_id as user_id data: - select * from nutrition_nutritionplan where user_id = bucket.user_id - by_plan_table: - parameters: SELECT id as plan_id FROM nutrition_nutritionplan WHERE user_id = token_parameters.user_id - data: - - SELECT * FROM nutrition_meal WHERE nutrition_meal.plan_id = bucket.plan_id - - select * from nutrition_logitem WHERE nutrition_logitem.plan_id = bucket.plan_id - # ingredient 1<->N log N-1 plan N-1 user - # post N-1 board N-1 user - # also - # mealItem has a meal_id and ingredient_id - # + - select * from ivm_nutrition_meal where user_id = bucket.user_id + - select * from ivm_nutrition_mealitem where user_id = bucket.user_id + - select * from ivm_nutrition_logitem where user_id = bucket.user_id + # "too many buckets" errors + # meal_item_ingredients: # note: we are restricted by <=1000 distinct ingredient_id values here + # parameters: select ingredient_id as ingredient_id FROM ivm_nutrition_mealitem WHERE user_id = token_parameters.user_id + # data: + # - select * from nutrition_ingredient WHERE ingredient_id = bucket.ingredient_id + # - select * from nutrition_image WHERE ingredient_id = bucket.ingredient_id + # log_item_ingredients: + # parameters: select ingredient_id as ingredient_id FROM ivm_nutrition_logitem WHERE user_id = token_parameters.user_id + # data: + # - select * from nutrition_ingredient WHERE ingredient_id = bucket.ingredient_id + # - select * from nutrition_image WHERE ingredient_id = bucket.ingredient_id From ecda257b4f111a43448649211c45c123576a83bd Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Thu, 17 Oct 2024 14:52:27 +0300 Subject: [PATCH 12/53] ivm aliases --- dev-postgres-powersync/config-powersync/sync_rules.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dev-postgres-powersync/config-powersync/sync_rules.yaml b/dev-postgres-powersync/config-powersync/sync_rules.yaml index d9ac9239b..7a563e80a 100644 --- a/dev-postgres-powersync/config-powersync/sync_rules.yaml +++ b/dev-postgres-powersync/config-powersync/sync_rules.yaml @@ -11,9 +11,9 @@ bucket_definitions: parameters: SELECT token_parameters.user_id as user_id data: - select * from nutrition_nutritionplan where user_id = bucket.user_id - - select * from ivm_nutrition_meal where user_id = bucket.user_id - - select * from ivm_nutrition_mealitem where user_id = bucket.user_id - - select * from ivm_nutrition_logitem where user_id = bucket.user_id + - select * from ivm_nutrition_meal as nutrition_meal where user_id = bucket.user_id + - select * from ivm_nutrition_mealitem as nutrition_mealitem where user_id = bucket.user_id + - select * from ivm_nutrition_logitem as nutrition_logitem where user_id = bucket.user_id # "too many buckets" errors # meal_item_ingredients: # note: we are restricted by <=1000 distinct ingredient_id values here # parameters: select ingredient_id as ingredient_id FROM ivm_nutrition_mealitem WHERE user_id = token_parameters.user_id From a0c83079d0b984329669b7e9642fc0fb07ac6377 Mon Sep 17 00:00:00 2001 From: Dieter Plaetinck Date: Thu, 31 Oct 2024 22:36:00 +0200 Subject: [PATCH 13/53] fix --- dev-postgres-powersync/config-powersync/sync_rules.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev-postgres-powersync/config-powersync/sync_rules.yaml b/dev-postgres-powersync/config-powersync/sync_rules.yaml index 7a563e80a..91c27cbea 100644 --- a/dev-postgres-powersync/config-powersync/sync_rules.yaml +++ b/dev-postgres-powersync/config-powersync/sync_rules.yaml @@ -10,7 +10,7 @@ bucket_definitions: by_user_id: parameters: SELECT token_parameters.user_id as user_id data: - - select * from nutrition_nutritionplan where user_id = bucket.user_id + - select * from ivm_nutrition_nutritionplan as nutrition_nutritionplan where user_id = bucket.user_id - select * from ivm_nutrition_meal as nutrition_meal where user_id = bucket.user_id - select * from ivm_nutrition_mealitem as nutrition_mealitem where user_id = bucket.user_id - select * from ivm_nutrition_logitem as nutrition_logitem where user_id = bucket.user_id From 36d6b1eb74299e122357eb55dea20d6f42300310 Mon Sep 17 00:00:00 2001 From: Roland Geider Date: Sun, 19 Oct 2025 15:56:49 +0200 Subject: [PATCH 14/53] Post merge fixes... --- config/prod.env | 17 +++++++++++++++++ dev/docker-compose.yml | 4 ---- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/config/prod.env b/config/prod.env index f17dd0895..72394aec2 100644 --- a/config/prod.env +++ b/config/prod.env @@ -184,6 +184,23 @@ FROM_EMAIL='wger Workout Manager ' # Needs a working email configuration # DJANGO_ADMINS=your name,email@example.com +# +# Django Rest Framework +# The number of proxies in front of the application. In the default configuration +# only nginx is. Change as approtriate if your setup differs. Also note that this +# is only used when throttling API requests. +NUMBER_OF_PROXIES=1 + +# +# Gunicorn +# +# Additional gunicorn options, change as needed. +# For the number of workers to spawn, a usually recommended value is (2 x $num_cores) + 1 +# see: +# - https://docs.gunicorn.org/en/stable/settings.html +# - https://github.com/wger-project/wger/blob/master/extras/docker/production/entrypoint.sh#L95 +GUNICORN_CMD_ARGS="--workers 3 --threads 2 --worker-class gthread --proxy-protocol True --timeout 240" + # # Powersync PS_PORT=8080 \ No newline at end of file diff --git a/dev/docker-compose.yml b/dev/docker-compose.yml index 2dc3c31ed..2ea704140 100644 --- a/dev/docker-compose.yml +++ b/dev/docker-compose.yml @@ -19,10 +19,6 @@ services: - ../config/prod.env - ../config/dev.env - ../config/dev-sqlite.env - volumes: - - type: bind - source: ${WGER_CODEPATH:?set the absolute path to the wger backend code in the .env file or env variable} - target: /home/wger/src ports: - "8000:8000" From 964909eb299dad2f06a887269010c5755b014d54 Mon Sep 17 00:00:00 2001 From: Roland Geider Date: Sun, 19 Oct 2025 15:58:01 +0200 Subject: [PATCH 15/53] Bump ivm version --- postgres/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/postgres/Dockerfile b/postgres/Dockerfile index 013057b65..0a2b15e8a 100644 --- a/postgres/Dockerfile +++ b/postgres/Dockerfile @@ -1,6 +1,6 @@ FROM postgres:15-bookworm AS builder -ENV VERSION=1.9 +ENV VERSION=1.12 RUN apt-get update && \ apt-get install -y \ From bb518ec6a0a08fecef299dfe6ecb42ce7b1b4940 Mon Sep 17 00:00:00 2001 From: Roland Geider Date: Fri, 24 Oct 2025 14:05:04 +0200 Subject: [PATCH 16/53] Add exercise tables to sync rules --- config/dev.env | 2 +- .../config-powersync/sync_rules.yaml | 29 +++++++++++++++---- dev-postgres-powersync/docker-compose.yml | 3 ++ 3 files changed, 27 insertions(+), 7 deletions(-) diff --git a/config/dev.env b/config/dev.env index 5a31537d7..479e76be3 100644 --- a/config/dev.env +++ b/config/dev.env @@ -5,7 +5,7 @@ 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=True # a couple of ingredients +LOAD_ONLINE_FIXTURES_ON_STARTUP=False # a couple of ingredients SYNC_INGREDIENTS_ON_STARTUP=False # lots of ingredients. expensive AXES_ENABLED=False diff --git a/dev-postgres-powersync/config-powersync/sync_rules.yaml b/dev-postgres-powersync/config-powersync/sync_rules.yaml index 91c27cbea..32c4b7caf 100644 --- a/dev-postgres-powersync/config-powersync/sync_rules.yaml +++ b/dev-postgres-powersync/config-powersync/sync_rules.yaml @@ -6,14 +6,31 @@ bucket_definitions: global: data: - - select * from exercises_muscle + # Core tables + - SELECT * FROM core_language + - SELECT * FROM core_license + + # Exercises + - 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 by_user_id: - parameters: SELECT token_parameters.user_id as user_id + parameters: SELECT token_parameters.user_id AS user_id data: - - select * from ivm_nutrition_nutritionplan as nutrition_nutritionplan where user_id = bucket.user_id - - select * from ivm_nutrition_meal as nutrition_meal where user_id = bucket.user_id - - select * from ivm_nutrition_mealitem as nutrition_mealitem where user_id = bucket.user_id - - select * from ivm_nutrition_logitem as nutrition_logitem where user_id = bucket.user_id + - SELECT uuid AS id, * FROM weight_weightentry WHERE user_id = bucket.user_id +# - select * from ivm_nutrition_nutritionplan as nutrition_nutritionplan where user_id = bucket.user_id +# - select * from ivm_nutrition_meal as nutrition_meal where user_id = bucket.user_id +# - select * from ivm_nutrition_mealitem as nutrition_mealitem where user_id = bucket.user_id +# - select * from ivm_nutrition_logitem as nutrition_logitem where user_id = bucket.user_id # "too many buckets" errors # meal_item_ingredients: # note: we are restricted by <=1000 distinct ingredient_id values here # parameters: select ingredient_id as ingredient_id FROM ivm_nutrition_mealitem WHERE user_id = token_parameters.user_id diff --git a/dev-postgres-powersync/docker-compose.yml b/dev-postgres-powersync/docker-compose.yml index a5aff29c4..8897afc01 100644 --- a/dev-postgres-powersync/docker-compose.yml +++ b/dev-postgres-powersync/docker-compose.yml @@ -41,6 +41,9 @@ services: - POSTGRES_DB=wger volumes: - postgres-dev-data:/var/lib/postgresql/data/ + # automatically import dump + #- ../wger-2025-09-09_19-25.dump:/docker-entrypoint-initdb.d/00-init-db.sql + #- ../wger-reset-password.sql:/docker-entrypoint-initdb.d/01-reset-pw.sql ports: - "5432:5432" expose: From ac59782b8cb91eb56c0d5ebdc667f43920b52ef0 Mon Sep 17 00:00:00 2001 From: Roland Geider Date: Sat, 25 Oct 2025 13:27:43 +0200 Subject: [PATCH 17/53] Update sync rules --- .../config-powersync/sync_rules.yaml | 3 +++ dev-postgres-powersync/docker-compose.yml | 20 ++++++++++++------- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/dev-postgres-powersync/config-powersync/sync_rules.yaml b/dev-postgres-powersync/config-powersync/sync_rules.yaml index 32c4b7caf..a40884f29 100644 --- a/dev-postgres-powersync/config-powersync/sync_rules.yaml +++ b/dev-postgres-powersync/config-powersync/sync_rules.yaml @@ -27,6 +27,9 @@ bucket_definitions: parameters: SELECT token_parameters.user_id AS user_id data: - SELECT uuid AS id, * FROM weight_weightentry WHERE user_id = bucket.user_id + - SELECT uuid AS id, * FROM manager_workoutlog WHERE user_id = bucket.user_id + - SELECT * FROM measurements_category WHERE user_id = bucket.user_id + # - select * from ivm_nutrition_nutritionplan as nutrition_nutritionplan where user_id = bucket.user_id # - select * from ivm_nutrition_meal as nutrition_meal where user_id = bucket.user_id # - select * from ivm_nutrition_mealitem as nutrition_mealitem where user_id = bucket.user_id diff --git a/dev-postgres-powersync/docker-compose.yml b/dev-postgres-powersync/docker-compose.yml index 8897afc01..2cb73fa9f 100644 --- a/dev-postgres-powersync/docker-compose.yml +++ b/dev-postgres-powersync/docker-compose.yml @@ -4,7 +4,7 @@ services: web: build: pull: true - context: ${WGER_CODEPATH} + context: ${WGER_CODEPATH:?set the absolute path to the wger backend code in the .env file or env variable} dockerfile: ./extras/docker/development/Dockerfile depends_on: db: @@ -12,10 +12,15 @@ services: env_file: - ../config/prod.env - ../config/dev.env - volumes: - - type: bind - source: ${WGER_CODEPATH:?set the absolute path to the wger backend code in the .env file or env variable} - target: /home/wger/src + 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 ports: - "8000:8000" @@ -42,8 +47,9 @@ services: volumes: - postgres-dev-data:/var/lib/postgresql/data/ # automatically import dump - #- ../wger-2025-09-09_19-25.dump:/docker-entrypoint-initdb.d/00-init-db.sql - #- ../wger-reset-password.sql:/docker-entrypoint-initdb.d/01-reset-pw.sql +# - ../wger-2025-09-09_19-25.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: From 9caca8dcf662009f7adfef6066f66f3b8ef8de00 Mon Sep 17 00:00:00 2001 From: Roland Geider Date: Wed, 5 Nov 2025 00:01:14 +0100 Subject: [PATCH 18/53] Configure the powersync URL This will get sent to the client along with the token --- config/dev.env | 1 + 1 file changed, 1 insertion(+) diff --git a/config/dev.env b/config/dev.env index 479e76be3..0bda3b4cb 100644 --- a/config/dev.env +++ b/config/dev.env @@ -14,3 +14,4 @@ AXES_ENABLED=False # --> 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 +POWERSYNC_URL=http://localhost:8080 From bd52d23d98fa858e3c4b6d7e84165e86bf2b467c Mon Sep 17 00:00:00 2001 From: Roland Geider Date: Wed, 5 Nov 2025 00:01:33 +0100 Subject: [PATCH 19/53] Bump mongo version --- dev-postgres-powersync/powersync-services/mongo.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dev-postgres-powersync/powersync-services/mongo.yaml b/dev-postgres-powersync/powersync-services/mongo.yaml index e01283655..9381497e2 100644 --- a/dev-postgres-powersync/powersync-services/mongo.yaml +++ b/dev-postgres-powersync/powersync-services/mongo.yaml @@ -1,7 +1,7 @@ services: # MongoDB Service used internally mongo: - image: mongo:7.0 + image: mongo:8 command: --replSet rs0 --bind_ip_all --quiet restart: unless-stopped ports: @@ -11,7 +11,7 @@ services: # Initializes the MongoDB replica set. This service will not usually be actively running mongo-rs-init: - image: mongo:7.0 + image: mongo:8 depends_on: - mongo restart: on-failure From 282d028e16bcf76e848aa72e1c7f283f3c695587 Mon Sep 17 00:00:00 2001 From: Roland Geider Date: Wed, 5 Nov 2025 00:01:53 +0100 Subject: [PATCH 20/53] Add missing data buckets --- dev-postgres-powersync/config-powersync/sync_rules.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/dev-postgres-powersync/config-powersync/sync_rules.yaml b/dev-postgres-powersync/config-powersync/sync_rules.yaml index a40884f29..f25c79044 100644 --- a/dev-postgres-powersync/config-powersync/sync_rules.yaml +++ b/dev-postgres-powersync/config-powersync/sync_rules.yaml @@ -3,12 +3,17 @@ # 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: 2 + bucket_definitions: global: data: # Core tables - SELECT * FROM core_language - SELECT * FROM core_license + - SELECT * FROM core_repetitionunit; + - SELECT * FROM core_weightunit; # Exercises - SELECT * FROM exercises_exercise @@ -28,6 +33,7 @@ bucket_definitions: data: - SELECT uuid AS id, * FROM weight_weightentry WHERE user_id = bucket.user_id - SELECT uuid AS id, * FROM manager_workoutlog WHERE user_id = bucket.user_id + - SELECT uuid AS id, * FROM manager_workoutsession WHERE user_id = bucket.user_id - SELECT * FROM measurements_category WHERE user_id = bucket.user_id # - select * from ivm_nutrition_nutritionplan as nutrition_nutritionplan where user_id = bucket.user_id From 0b1cbac3ca36e5b17bf547ba6339f5e783a720f8 Mon Sep 17 00:00:00 2001 From: Roland Geider Date: Sun, 23 Nov 2025 13:32:25 +0100 Subject: [PATCH 21/53] When using an android emulator use the internal ip --- config/dev.env | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/config/dev.env b/config/dev.env index 0bda3b4cb..9800396a1 100644 --- a/config/dev.env +++ b/config/dev.env @@ -14,4 +14,9 @@ AXES_ENABLED=False # --> 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 -POWERSYNC_URL=http://localhost:8080 + +# When developing on the android emulator +POWERSYNC_URL=http://10.0.2.2:8080 + +# Othwise +#POWERSYNC_URL=http://localhost:8080 From d89ae8a581013e6b457642d7a60e364c6f5bddef Mon Sep 17 00:00:00 2001 From: Roland Geider Date: Fri, 20 Feb 2026 18:40:24 +0100 Subject: [PATCH 22/53] Move the initialization of the replica set to the health check This allows us to remove the other mongo service --- .../powersync-services/mongo.yaml | 15 ++++----------- .../powersync-services/powersync.yaml | 2 +- 2 files changed, 5 insertions(+), 12 deletions(-) diff --git a/dev-postgres-powersync/powersync-services/mongo.yaml b/dev-postgres-powersync/powersync-services/mongo.yaml index 9381497e2..e7d64a55e 100644 --- a/dev-postgres-powersync/powersync-services/mongo.yaml +++ b/dev-postgres-powersync/powersync-services/mongo.yaml @@ -8,17 +8,10 @@ services: - 27017:27017 volumes: - mongo_storage:/data/db - - # Initializes the MongoDB replica set. This service will not usually be actively running - mongo-rs-init: - image: mongo:8 - depends_on: - - mongo - restart: on-failure - entrypoint: - - bash - - -c - - 'mongosh --host mongo:27017 --eval ''try{rs.status().ok && quit(0)} catch {} rs.initiate({_id: "rs0", version: 1, members: [{ _id: 0, host : "mongo:27017" }]})''' + 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: 10s + start_period: 5s volumes: mongo_storage: diff --git a/dev-postgres-powersync/powersync-services/powersync.yaml b/dev-postgres-powersync/powersync-services/powersync.yaml index 14096ccce..6e779b24f 100644 --- a/dev-postgres-powersync/powersync-services/powersync.yaml +++ b/dev-postgres-powersync/powersync-services/powersync.yaml @@ -1,7 +1,7 @@ services: powersync: depends_on: - mongo-rs-init: + mongo: condition: service_completed_successfully restart: unless-stopped image: journeyapps/powersync-service:latest From bc6386804dc39064bc7050eadd0196411fbcb5a0 Mon Sep 17 00:00:00 2001 From: Roland Geider Date: Thu, 12 Mar 2026 13:34:50 +0100 Subject: [PATCH 23/53] Use the "docker.io" prefix for image names for consistency --- dev-postgres-powersync/docker-compose.yml | 2 +- dev-postgres-powersync/powersync-services/mongo.yaml | 2 +- dev-postgres-powersync/powersync-services/powersync.yaml | 6 +++++- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/dev-postgres-powersync/docker-compose.yml b/dev-postgres-powersync/docker-compose.yml index 2cb73fa9f..51147d525 100644 --- a/dev-postgres-powersync/docker-compose.yml +++ b/dev-postgres-powersync/docker-compose.yml @@ -25,7 +25,7 @@ services: - "8000:8000" cache: - image: redis + image: docker.io/redis:latest expose: - 6379 healthcheck: diff --git a/dev-postgres-powersync/powersync-services/mongo.yaml b/dev-postgres-powersync/powersync-services/mongo.yaml index e7d64a55e..bd5988b40 100644 --- a/dev-postgres-powersync/powersync-services/mongo.yaml +++ b/dev-postgres-powersync/powersync-services/mongo.yaml @@ -1,7 +1,7 @@ services: # MongoDB Service used internally mongo: - image: mongo:8 + image: docker.io/mongo:8 command: --replSet rs0 --bind_ip_all --quiet restart: unless-stopped ports: diff --git a/dev-postgres-powersync/powersync-services/powersync.yaml b/dev-postgres-powersync/powersync-services/powersync.yaml index 6e779b24f..006cdaeb4 100644 --- a/dev-postgres-powersync/powersync-services/powersync.yaml +++ b/dev-postgres-powersync/powersync-services/powersync.yaml @@ -4,7 +4,8 @@ services: mongo: condition: service_completed_successfully restart: unless-stopped - image: journeyapps/powersync-service:latest + + image: docker.io/journeyapps/powersync-service:latest # The unified service runs an API server and replication worker in the same container. # These services can be executed in different containers by using individual entry commands e.g. # Start only the API server with @@ -21,13 +22,16 @@ services: # command: ['migrate', 'up'] # Note that this container must finish executing before starting the sync or unified container. command: ["start", "-r", "unified"] + volumes: # Mounts the specified config folder to the container # This folder should contain `powersync.yaml and sync_rules.yaml - ../config-powersync:/config + env_file: - ../../config/prod.env - ../../config/dev.env + environment: # This is the path (inside the container) to the YAML config file # Alternatively the config path can be specified in the command From 638220e34f5743d2f04922503b8f4788b8ac0f43 Mon Sep 17 00:00:00 2001 From: Roland Geider Date: Thu, 12 Mar 2026 15:56:21 +0100 Subject: [PATCH 24/53] Option doesn't exist anymore This would make the startup take several hours to complete --- config/dev.env | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/config/dev.env b/config/dev.env index 566438a35..b8709ba9d 100644 --- a/config/dev.env +++ b/config/dev.env @@ -6,7 +6,6 @@ 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 -SYNC_INGREDIENTS_ON_STARTUP=False # lots of ingredients. expensive AXES_ENABLED=False DJANGO_STORAGES_STATICFILES_BACKEND=django.contrib.staticfiles.storage.StaticFilesStorage @@ -17,7 +16,7 @@ POWERSYNC_JWKS_PUBLIC_KEY=eyJhbGciOiAiUlMyNTYiLCAia3R5IjogIlJTQSIsICJuIjogInFhdV POWERSYNC_JWKS_PRIVATE_KEY=eyJhbGciOiAiUlMyNTYiLCAia3R5IjogIlJTQSIsICJuIjogInFhdVVnb0ZXenRNcjVEYks3bFIxZXUxazJrdllyblJkRGh1NDFyWnFLeWhDWkJya0FTS0d0N25KbVUwVEpKb1d0cFF2eHVvc0ZGeW1BMUhXQnNaY0dtVlcxdlowdDJlazl4THg5bjg2UWRIVWc1MktsRG9ZUzNtRTFaWW5BYzJfRDM3UmxyQkVxRXpuSnBNeDJ3VkpLcVdRZHlWSWh6Q082YzRnOWN3VExGbUhkVXVURXMzdDNBN1MyNENrUkM2TE1KSFFvRTJzay1uWlJyZE9fTHVNNUJJcVp2b1dWUC1Salp4OWk4OGdaaDhvOEcyWW1xZnMwczRzYW1fam85bmFaYlo4aFBFQ0FZdnZUZ29ObzRHMGpXZERZeGdPWHlXTE80bTk1SEdMSFJMZjZ5M29vdkZad2QwN2FFbThEU3dBX3hsY1V4WHNNZ0ZlYVVVZkp2NEV4USIsICJlIjogIkFRQUIiLCAiZCI6ICJQZXVwNjhUakZ1RVhaQmFoRWNDT0RWcEUwNndaZkhWb0hvVjhmQk9maEhlUlh6STNJcmprZkhtWHV0UlhsNlNLaElCcFBVbHA0OVo2R2IwTWhIVncySXRDV1hvaFYydkNWdzg1Y2RHMXc1NmQxWml4b2UzZnZ1LXV6RG9icXp0WXJvR0VZTi1jZHVWMS1HeUFwZU4wYzlWdmR5UUtwNWZQbUVGTFl4amlxR3k5UUhyTldpcGJmZXdPUGY0YUl4X05VRnE3R1BsUk1yalA4VEhvSzNPOVNfXzJpR09LRVpINDFUWkpscVBZX0s5dFNkbFNKd1FPWEtwOFc2ZUdGT3l2MElueVhsUXhHb0ZBWVNrUC12WTlWQy1vTUtzdmhocm1GeGM0VlU2OUZ3VWFJYUdaOU9jaXF4M3B0aE9sU1drRjFhbEtxNWFJZ2VHbEUzM2VyNGthSXciLCAicCI6ICI1WDN0QzN4Z0hwbm91U1JwSlg4c0ZWRm5vamhxMWJoWkF3c3VRaXBxWWgtZmJNRGI4a2NTTy1fT3BEMExNekYzcHp0dVNRb0NZOFc0WjI0TEJ6cFRuUlFid0JrYWt3VDMybmZIU1J0d3RnM1ZjWkkxZFNsdHgtclhEcHlBMDNHa1RvLUxEZkp1UzF0a1FYQXB0OTBkcnJHMndjQ25oRXc4bGx2SzR2cWRucHMiLCAicSI6ICJ2VVM2V2QtY2trTUJMVmJvSkVaVnRtMlFLTFE2dV9oZEFrbTFWa3dGajMxZWZWRTlFRWRSa0F0dGVoOWh2ZzBkM2FXVDZ1bFQ4YlpubWo3WkFjNG55aVdwOTlFd0k5U0hFX01UUE11YVZSeUw5SmFIX2R0Uk5nVGE5UV9hZUs2d1pkY3RwLUZRT1lteVlDWmhzRnVOTG45TFJ3UklJOVJ0YlBXYW55X01jQjgiLCAiZHAiOiAiWjFNNkhmakN3aVJqcnJBaEV6dmQyajlMbkxNd0RzZXdjX2xkdTNhamJVaDFuQjU5S09rczRZV0lFVlJXclpieEczOWJtVkVEWUc2T0p5dFpsY2lDQ3ZBWnluVEREVHlvWjFtVWhXcndaVmQzS1dvOTNXRm94eUVKOE04d0JZTmVDZTBCRzZkeVYwVnZyekxUNWEtTmhMRUk2dFZWMXZBSU8xNWF5N1V3c0U4IiwgImRxIjogIktsclpBUWZEZUEtNmtiVGpHa3NMSDFvQmFycDZjbG93SmpUc2ViVmxnU2pqSGxReHdCVFZzZEI4M1Zsc2ZDVmZTNXlrTDJ1cnQybkVZWVl5OWU1MmhReE1yd0tITFYyQUpQeS1qMXBZM1RjWU10SUUtTkE5cWtNSDVOTjVab3hoT1VrZ0ZIT2RpbUxBSWpnMG9FeThtVzB2SVdOWjZYcS1TaVhrUmo5aUZxMCIsICJxaSI6ICJzSV84RTh0MTBsRDY2NTh3UXRpY19BaUUxOVk1Rms0SDJWbnpGclBhVU04aWFNaVc2eUZxMFZuN3RXa2RTWS1STTB1SFMwdmVmSEcyZTBKSWxEanhBUmZWZUcwNTFyVUNRZjBkSnR4U0ZDQUp2eGxMRTZsYjZOQlUwZVIyMld6bjVob1ZZTVpHZnQ5QnA0SlVOOHJkMF9lMm1kSjhxc09wM1NLQ3NTSTByUkkiLCAia2lkIjogInBvd2Vyc3luYyJ9 # When developing on the android emulator -POWERSYNC_URL=http://10.0.2.2:8080 +#POWERSYNC_URL=http://10.0.2.2:8080 # Othwise -#POWERSYNC_URL=http://localhost:8080 +POWERSYNC_URL=http://localhost:8080 From 6346baca8bd744fb24816db43c1f0ab447780e5f Mon Sep 17 00:00:00 2001 From: Roland Geider Date: Thu, 12 Mar 2026 15:57:13 +0100 Subject: [PATCH 25/53] No need to compile pg_ivm, this is not used anymore --- dev-postgres-powersync/docker-compose.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/dev-postgres-powersync/docker-compose.yml b/dev-postgres-powersync/docker-compose.yml index 51147d525..546d96c14 100644 --- a/dev-postgres-powersync/docker-compose.yml +++ b/dev-postgres-powersync/docker-compose.yml @@ -37,9 +37,7 @@ services: restart: unless-stopped db: - build: - context: ../postgres - dockerfile: Dockerfile + image: docker.io/postgres:15-alpine environment: - POSTGRES_USER=wger - POSTGRES_PASSWORD=wger From d041bac823af11879c6cb7a74f65db5f890b6c76 Mon Sep 17 00:00:00 2001 From: Roland Geider Date: Sat, 14 Mar 2026 12:39:58 +0100 Subject: [PATCH 26/53] Move sync rules to streams, which finally support JOINs --- .../config-powersync/sync_rules.yaml | 95 +++++++++++++------ 1 file changed, 64 insertions(+), 31 deletions(-) diff --git a/dev-postgres-powersync/config-powersync/sync_rules.yaml b/dev-postgres-powersync/config-powersync/sync_rules.yaml index f25c79044..41f740bc1 100644 --- a/dev-postgres-powersync/config-powersync/sync_rules.yaml +++ b/dev-postgres-powersync/config-powersync/sync_rules.yaml @@ -3,19 +3,20 @@ # 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: 2 + edition: 3 -bucket_definitions: - global: - data: - # Core tables +# 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; - - # Exercises + - SELECT * FROM core_repetitionunit + - SELECT * FROM core_weightunit - SELECT * FROM exercises_exercise - SELECT * FROM exercises_translation - SELECT * FROM exercises_alias @@ -28,26 +29,58 @@ bucket_definitions: - SELECT * FROM exercises_exerciseimage - SELECT * FROM exercises_exercisevideo - SELECT * FROM exercises_variation - by_user_id: - parameters: SELECT token_parameters.user_id AS user_id - data: - - SELECT uuid AS id, * FROM weight_weightentry WHERE user_id = bucket.user_id - - SELECT uuid AS id, * FROM manager_workoutlog WHERE user_id = bucket.user_id - - SELECT uuid AS id, * FROM manager_workoutsession WHERE user_id = bucket.user_id - - SELECT * FROM measurements_category WHERE user_id = bucket.user_id -# - select * from ivm_nutrition_nutritionplan as nutrition_nutritionplan where user_id = bucket.user_id -# - select * from ivm_nutrition_meal as nutrition_meal where user_id = bucket.user_id -# - select * from ivm_nutrition_mealitem as nutrition_mealitem where user_id = bucket.user_id -# - select * from ivm_nutrition_logitem as nutrition_logitem where user_id = bucket.user_id - # "too many buckets" errors - # meal_item_ingredients: # note: we are restricted by <=1000 distinct ingredient_id values here - # parameters: select ingredient_id as ingredient_id FROM ivm_nutrition_mealitem WHERE user_id = token_parameters.user_id - # data: - # - select * from nutrition_ingredient WHERE ingredient_id = bucket.ingredient_id - # - select * from nutrition_image WHERE ingredient_id = bucket.ingredient_id - # log_item_ingredients: - # parameters: select ingredient_id as ingredient_id FROM ivm_nutrition_logitem WHERE user_id = token_parameters.user_id - # data: - # - select * from nutrition_ingredient WHERE ingredient_id = bucket.ingredient_id - # - select * from nutrition_image WHERE ingredient_id = bucket.ingredient_id + 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() + ); \ No newline at end of file From 5eafccd4b4db3cf313aab3beecdac57689d2f1f6 Mon Sep 17 00:00:00 2001 From: Roland Geider Date: Sat, 14 Mar 2026 12:40:15 +0100 Subject: [PATCH 27/53] Cleanup --- config/dev.env | 2 +- dev-postgres-powersync/docker-compose.yml | 18 +++++++++--------- .../powersync-services/mongo.yaml | 11 +++++++++-- 3 files changed, 19 insertions(+), 12 deletions(-) diff --git a/config/dev.env b/config/dev.env index b8709ba9d..1f59df47f 100644 --- a/config/dev.env +++ b/config/dev.env @@ -18,5 +18,5 @@ POWERSYNC_JWKS_PRIVATE_KEY=eyJhbGciOiAiUlMyNTYiLCAia3R5IjogIlJTQSIsICJuIjogInFhd # When developing on the android emulator #POWERSYNC_URL=http://10.0.2.2:8080 -# Othwise +# Otherwise POWERSYNC_URL=http://localhost:8080 diff --git a/dev-postgres-powersync/docker-compose.yml b/dev-postgres-powersync/docker-compose.yml index 546d96c14..694509d7c 100644 --- a/dev-postgres-powersync/docker-compose.yml +++ b/dev-postgres-powersync/docker-compose.yml @@ -6,12 +6,6 @@ services: 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 - depends_on: - db: - condition: service_healthy - env_file: - - ../config/prod.env - - ../config/dev.env develop: watch: - action: sync @@ -21,6 +15,12 @@ services: 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" @@ -45,9 +45,9 @@ services: volumes: - postgres-dev-data:/var/lib/postgresql/data/ # automatically import dump -# - ../wger-2025-09-09_19-25.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 + #- ../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: diff --git a/dev-postgres-powersync/powersync-services/mongo.yaml b/dev-postgres-powersync/powersync-services/mongo.yaml index bd5988b40..4be468ea4 100644 --- a/dev-postgres-powersync/powersync-services/mongo.yaml +++ b/dev-postgres-powersync/powersync-services/mongo.yaml @@ -9,8 +9,15 @@ services: 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: 10s + 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: From 895dab6523cb4bf73d8e1f48bc9b23a0657d952a Mon Sep 17 00:00:00 2001 From: Roland Geider Date: Thu, 19 Mar 2026 21:44:04 +0100 Subject: [PATCH 28/53] Update sync rules --- .../config-powersync/sync_rules.yaml | 79 +++++++++++-------- 1 file changed, 44 insertions(+), 35 deletions(-) diff --git a/dev-postgres-powersync/config-powersync/sync_rules.yaml b/dev-postgres-powersync/config-powersync/sync_rules.yaml index 41f740bc1..216852b71 100644 --- a/dev-postgres-powersync/config-powersync/sync_rules.yaml +++ b/dev-postgres-powersync/config-powersync/sync_rules.yaml @@ -4,15 +4,15 @@ # The service needs to be restarted for changes to take effect. # Warning, parameter queries have a limit of 1000 rows (before filtering)! +# For details, see the documentation: https://docs.powersync.com/sync/streams/overview config: edition: 3 -# For details, see the documentation: https://docs.powersync.com/sync/streams/overview streams: + # Core data, common to all users core: auto_subscribe: true queries: - # Translated from "global" bucket definition. - SELECT * FROM core_language - SELECT * FROM core_license - SELECT * FROM core_repetitionunit @@ -32,6 +32,38 @@ streams: user_streams: auto_subscribe: true + with: + user_ingredients: | + SELECT DISTINCT + nutrition_ingredient.id + 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() + ) queries: # Weight - "SELECT uuid AS id, * FROM weight_weightentry WHERE user_id = auth.user_id()" @@ -46,41 +78,18 @@ streams: - | 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() + 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 * FROM nutrition_ingredient WHERE id IN user_ingredients - | - SELECT DISTINCT - nutrition_ingredient.* + SELECT nutrition_image.* 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() - ); \ No newline at end of file + nutrition_image + JOIN + nutrition_ingredient ON nutrition_ingredient.id = nutrition_image.ingredient_id + WHERE nutrition_ingredient.id IN user_ingredients From 5bd493a9558e83280265b9f36b10ab19a6f5c2ae Mon Sep 17 00:00:00 2001 From: Roland Geider Date: Fri, 17 Apr 2026 13:01:22 +0200 Subject: [PATCH 29/53] Removed variation table This information is now available on the exercise itself --- dev-postgres-powersync/config-powersync/sync_rules.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/dev-postgres-powersync/config-powersync/sync_rules.yaml b/dev-postgres-powersync/config-powersync/sync_rules.yaml index 216852b71..f0e70aae0 100644 --- a/dev-postgres-powersync/config-powersync/sync_rules.yaml +++ b/dev-postgres-powersync/config-powersync/sync_rules.yaml @@ -28,7 +28,6 @@ streams: - SELECT * FROM exercises_exercisecategory - SELECT * FROM exercises_exerciseimage - SELECT * FROM exercises_exercisevideo - - SELECT * FROM exercises_variation user_streams: auto_subscribe: true From bee2813785ca2b3ad9a70cb98b367633bc8bac79 Mon Sep 17 00:00:00 2001 From: Roland Geider Date: Sat, 18 Apr 2026 20:40:50 +0200 Subject: [PATCH 30/53] Correctly read out the log and session entries --- dev-postgres-powersync/config-powersync/sync_rules.yaml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/dev-postgres-powersync/config-powersync/sync_rules.yaml b/dev-postgres-powersync/config-powersync/sync_rules.yaml index f0e70aae0..230a99d02 100644 --- a/dev-postgres-powersync/config-powersync/sync_rules.yaml +++ b/dev-postgres-powersync/config-powersync/sync_rules.yaml @@ -68,11 +68,10 @@ streams: - "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()" + - "SELECT * FROM manager_workoutlog WHERE user_id = auth.user_id()" + - "SELECT * 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 From d6539440b1aa237f9884619f95cd1ba07770c1e7 Mon Sep 17 00:00:00 2001 From: Roland Geider Date: Mon, 20 Apr 2026 23:02:56 +0200 Subject: [PATCH 31/53] Cast IDs as strings This was preventing some syncs from happening --- .../config-powersync/sync_rules.yaml | 33 ++++++++++++------- 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/dev-postgres-powersync/config-powersync/sync_rules.yaml b/dev-postgres-powersync/config-powersync/sync_rules.yaml index 230a99d02..1f0e52c72 100644 --- a/dev-postgres-powersync/config-powersync/sync_rules.yaml +++ b/dev-postgres-powersync/config-powersync/sync_rules.yaml @@ -29,6 +29,14 @@ streams: - SELECT * FROM exercises_exerciseimage - SELECT * FROM exercises_exercisevideo + # + # IMPORTANT: + # + # `CAST(user_id AS TEXT)` is required because `auth.user_id()` comes + # from the JWT `sub` claim as a string. Without the cast, PowerSync + # stores the bucket key as integer but announces it to the client as + # string — the client then never finds any ops in the "empty" bucket. + user_streams: auto_subscribe: true with: @@ -47,7 +55,7 @@ streams: JOIN nutrition_nutritionplan ON nutrition_logitem.plan_id = nutrition_nutritionplan.id WHERE - nutrition_nutritionplan.user_id = auth.user_id() + CAST(nutrition_nutritionplan.user_id AS TEXT) = auth.user_id() ) OR -- ingredients added to nutritional plans @@ -61,25 +69,25 @@ streams: JOIN nutrition_nutritionplan ON nutrition_meal.plan_id = nutrition_nutritionplan.id WHERE - nutrition_nutritionplan.user_id = auth.user_id() + CAST(nutrition_nutritionplan.user_id AS TEXT) = auth.user_id() ) queries: # Weight - - "SELECT uuid AS id, * FROM weight_weightentry WHERE user_id = auth.user_id()" + - "SELECT uuid AS id, weight, date, user_id FROM weight_weightentry WHERE CAST(user_id AS TEXT) = auth.user_id()" # Routines - - "SELECT * FROM manager_workoutlog WHERE user_id = auth.user_id()" - - "SELECT * FROM manager_workoutsession WHERE user_id = auth.user_id()" + - "SELECT * FROM manager_workoutlog WHERE CAST(user_id AS TEXT) = auth.user_id()" + - "SELECT * FROM manager_workoutsession WHERE CAST(user_id AS TEXT) = auth.user_id()" # Measurements - - "SELECT * FROM measurements_category WHERE user_id = auth.user_id()" + - "SELECT * FROM measurements_category WHERE CAST(user_id AS TEXT) = 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() + SELECT + measurements_measurement.* + FROM measurements_measurement + INNER JOIN measurements_category + ON measurements_measurement.category_id = measurements_category.id + WHERE CAST(measurements_category.user_id AS TEXT) = auth.user_id() # Nutrition # note: we are restricted by <=1000 distinct ingredient_id values here @@ -91,3 +99,4 @@ streams: JOIN nutrition_ingredient ON nutrition_ingredient.id = nutrition_image.ingredient_id WHERE nutrition_ingredient.id IN user_ingredients + From 92f5e7b97e474af698f3b64b1d90b72ebc828ad6 Mon Sep 17 00:00:00 2001 From: Roland Geider Date: Mon, 20 Apr 2026 23:03:15 +0200 Subject: [PATCH 32/53] Cleanup --- config/dev.env | 3 +++ dev-postgres-powersync/powersync-services/mongo.yaml | 2 +- dev-postgres-powersync/powersync-services/powersync.yaml | 4 ++-- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/config/dev.env b/config/dev.env index 1f59df47f..b46428d58 100644 --- a/config/dev.env +++ b/config/dev.env @@ -20,3 +20,6 @@ POWERSYNC_JWKS_PRIVATE_KEY=eyJhbGciOiAiUlMyNTYiLCAia3R5IjogIlJTQSIsICJuIjogInFhd # Otherwise POWERSYNC_URL=http://localhost:8080 + +SECRET_KEY='dev1-docker-supersecret-key-1234567890!@#$%^&*(-_)+=' +SIGNING_KEY='dev1-docker-secret-jwtkey-1234567890!@#$%^&*(-_=+)' diff --git a/dev-postgres-powersync/powersync-services/mongo.yaml b/dev-postgres-powersync/powersync-services/mongo.yaml index 4be468ea4..5c2bc8ae5 100644 --- a/dev-postgres-powersync/powersync-services/mongo.yaml +++ b/dev-postgres-powersync/powersync-services/mongo.yaml @@ -5,7 +5,7 @@ services: command: --replSet rs0 --bind_ip_all --quiet restart: unless-stopped ports: - - 27017:27017 + - "27017:27017" volumes: - mongo_storage:/data/db healthcheck: diff --git a/dev-postgres-powersync/powersync-services/powersync.yaml b/dev-postgres-powersync/powersync-services/powersync.yaml index 006cdaeb4..1488b92b2 100644 --- a/dev-postgres-powersync/powersync-services/powersync.yaml +++ b/dev-postgres-powersync/powersync-services/powersync.yaml @@ -13,7 +13,7 @@ services: # Start only the replication worker with # command: ['start', '-r', 'sync'] - # Migations occur automatically by default. Default migrations can be disabled in `powersync.yaml`: + # Migrations occur automatically by default. Default migrations can be disabled in `powersync.yaml`: # migrations: # disable_auto_migration: true # @@ -53,4 +53,4 @@ services: PS_JWKS_URL: http://web:8000/api/v2/powersync-keys ports: - - 8080:8080 + - "8080:8080" From e8e2766b59beecfc2e1dc856c0e7b3e5acdbc3ff Mon Sep 17 00:00:00 2001 From: Roland Geider Date: Tue, 21 Apr 2026 14:51:09 +0200 Subject: [PATCH 33/53] Cleanup and consolidate configs --- config/dev.env | 16 ++++--------- config/prod.env | 17 ++++++++----- .../config-powersync/powersync.yaml | 22 ++++++----------- dev-postgres-powersync/docker-compose.yml | 1 - .../powersync-services/mongo.yaml | 24 ------------------- .../powersync-services/powersync.yaml | 20 ++++++++++++++-- 6 files changed, 41 insertions(+), 59 deletions(-) delete mode 100644 dev-postgres-powersync/powersync-services/mongo.yaml diff --git a/config/dev.env b/config/dev.env index b46428d58..8a6c49366 100644 --- a/config/dev.env +++ b/config/dev.env @@ -9,17 +9,11 @@ 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 +# These can be generated with docker compose exec web ./manage.py generate-powersync-keys +#POWERSYNC_JWKS_PUBLIC_KEY=eyJhbGciOiAiUlMyNTYiLCAia3R5IjogIlJTQSIsICJuIjogInFhdVVnb0ZXenRNcjVEYks3bFIxZXUxazJrdllyblJkRGh1NDFyWnFLeWhDWkJya0FTS0d0N25KbVUwVEpKb1d0cFF2eHVvc0ZGeW1BMUhXQnNaY0dtVlcxdlowdDJlazl4THg5bjg2UWRIVWc1MktsRG9ZUzNtRTFaWW5BYzJfRDM3UmxyQkVxRXpuSnBNeDJ3VkpLcVdRZHlWSWh6Q082YzRnOWN3VExGbUhkVXVURXMzdDNBN1MyNENrUkM2TE1KSFFvRTJzay1uWlJyZE9fTHVNNUJJcVp2b1dWUC1Salp4OWk4OGdaaDhvOEcyWW1xZnMwczRzYW1fam85bmFaYlo4aFBFQ0FZdnZUZ29ObzRHMGpXZERZeGdPWHlXTE80bTk1SEdMSFJMZjZ5M29vdkZad2QwN2FFbThEU3dBX3hsY1V4WHNNZ0ZlYVVVZkp2NEV4USIsICJlIjogIkFRQUIiLCAia2lkIjogInBvd2Vyc3luYyJ9 +#POWERSYNC_JWKS_PRIVATE_KEY=eyJhbGciOiAiUlMyNTYiLCAia3R5IjogIlJTQSIsICJuIjogInFhdVVnb0ZXenRNcjVEYks3bFIxZXUxazJrdllyblJkRGh1NDFyWnFLeWhDWkJya0FTS0d0N25KbVUwVEpKb1d0cFF2eHVvc0ZGeW1BMUhXQnNaY0dtVlcxdlowdDJlazl4THg5bjg2UWRIVWc1MktsRG9ZUzNtRTFaWW5BYzJfRDM3UmxyQkVxRXpuSnBNeDJ3VkpLcVdRZHlWSWh6Q082YzRnOWN3VExGbUhkVXVURXMzdDNBN1MyNENrUkM2TE1KSFFvRTJzay1uWlJyZE9fTHVNNUJJcVp2b1dWUC1Salp4OWk4OGdaaDhvOEcyWW1xZnMwczRzYW1fam85bmFaYlo4aFBFQ0FZdnZUZ29ObzRHMGpXZERZeGdPWHlXTE80bTk1SEdMSFJMZjZ5M29vdkZad2QwN2FFbThEU3dBX3hsY1V4WHNNZ0ZlYVVVZkp2NEV4USIsICJlIjogIkFRQUIiLCAiZCI6ICJQZXVwNjhUakZ1RVhaQmFoRWNDT0RWcEUwNndaZkhWb0hvVjhmQk9maEhlUlh6STNJcmprZkhtWHV0UlhsNlNLaElCcFBVbHA0OVo2R2IwTWhIVncySXRDV1hvaFYydkNWdzg1Y2RHMXc1NmQxWml4b2UzZnZ1LXV6RG9icXp0WXJvR0VZTi1jZHVWMS1HeUFwZU4wYzlWdmR5UUtwNWZQbUVGTFl4amlxR3k5UUhyTldpcGJmZXdPUGY0YUl4X05VRnE3R1BsUk1yalA4VEhvSzNPOVNfXzJpR09LRVpINDFUWkpscVBZX0s5dFNkbFNKd1FPWEtwOFc2ZUdGT3l2MElueVhsUXhHb0ZBWVNrUC12WTlWQy1vTUtzdmhocm1GeGM0VlU2OUZ3VWFJYUdaOU9jaXF4M3B0aE9sU1drRjFhbEtxNWFJZ2VHbEUzM2VyNGthSXciLCAicCI6ICI1WDN0QzN4Z0hwbm91U1JwSlg4c0ZWRm5vamhxMWJoWkF3c3VRaXBxWWgtZmJNRGI4a2NTTy1fT3BEMExNekYzcHp0dVNRb0NZOFc0WjI0TEJ6cFRuUlFid0JrYWt3VDMybmZIU1J0d3RnM1ZjWkkxZFNsdHgtclhEcHlBMDNHa1RvLUxEZkp1UzF0a1FYQXB0OTBkcnJHMndjQ25oRXc4bGx2SzR2cWRucHMiLCAicSI6ICJ2VVM2V2QtY2trTUJMVmJvSkVaVnRtMlFLTFE2dV9oZEFrbTFWa3dGajMxZWZWRTlFRWRSa0F0dGVoOWh2ZzBkM2FXVDZ1bFQ4YlpubWo3WkFjNG55aVdwOTlFd0k5U0hFX01UUE11YVZSeUw5SmFIX2R0Uk5nVGE5UV9hZUs2d1pkY3RwLUZRT1lteVlDWmhzRnVOTG45TFJ3UklJOVJ0YlBXYW55X01jQjgiLCAiZHAiOiAiWjFNNkhmakN3aVJqcnJBaEV6dmQyajlMbkxNd0RzZXdjX2xkdTNhamJVaDFuQjU5S09rczRZV0lFVlJXclpieEczOWJtVkVEWUc2T0p5dFpsY2lDQ3ZBWnluVEREVHlvWjFtVWhXcndaVmQzS1dvOTNXRm94eUVKOE04d0JZTmVDZTBCRzZkeVYwVnZyekxUNWEtTmhMRUk2dFZWMXZBSU8xNWF5N1V3c0U4IiwgImRxIjogIktsclpBUWZEZUEtNmtiVGpHa3NMSDFvQmFycDZjbG93SmpUc2ViVmxnU2pqSGxReHdCVFZzZEI4M1Zsc2ZDVmZTNXlrTDJ1cnQybkVZWVl5OWU1MmhReE1yd0tITFYyQUpQeS1qMXBZM1RjWU10SUUtTkE5cWtNSDVOTjVab3hoT1VrZ0ZIT2RpbUxBSWpnMG9FeThtVzB2SVdOWjZYcS1TaVhrUmo5aUZxMCIsICJxaSI6ICJzSV84RTh0MTBsRDY2NTh3UXRpY19BaUUxOVk1Rms0SDJWbnpGclBhVU04aWFNaVc2eUZxMFZuN3RXa2RTWS1STTB1SFMwdmVmSEcyZTBKSWxEanhBUmZWZUcwNTFyVUNRZjBkSnR4U0ZDQUp2eGxMRTZsYjZOQlUwZVIyMld6bjVob1ZZTVpHZnQ5QnA0SlVOOHJkMF9lMm1kSjhxc09wM1NLQ3NTSTByUkkiLCAia2lkIjogInBvd2Vyc3luYyJ9 +#POWERSYNC_URL=http://localhost:8080 +#POWERSYNC_URL=http://10.0.2.2:8080 # When developing on the android emulator SECRET_KEY='dev1-docker-supersecret-key-1234567890!@#$%^&*(-_)+=' SIGNING_KEY='dev1-docker-secret-jwtkey-1234567890!@#$%^&*(-_=+)' diff --git a/config/prod.env b/config/prod.env index 3169604fb..25258a5af 100644 --- a/config/prod.env +++ b/config/prod.env @@ -9,6 +9,12 @@ SECRET_KEY=wger-docker-supersecret-key-1234567890!@#$%^&*(-_) # Signing key used for JWT, use something different than the secret key SIGNING_KEY=wger-docker-secret-jwtkey-1234567890!@#$%^&*(-_=+) +# Powersync JWT keys, used by the mobile app. This default NEEDS to be changed. +# New keys can be generated with: docker compose exec web ./manage.py generate-powersync-keys +POWERSYNC_JWKS_PUBLIC_KEY=eyJhbGciOiAiUlMyNTYiLCAia3R5IjogIlJTQSIsICJuIjogInFhdVVnb0ZXenRNcjVEYks3bFIxZXUxazJrdllyblJkRGh1NDFyWnFLeWhDWkJya0FTS0d0N25KbVUwVEpKb1d0cFF2eHVvc0ZGeW1BMUhXQnNaY0dtVlcxdlowdDJlazl4THg5bjg2UWRIVWc1MktsRG9ZUzNtRTFaWW5BYzJfRDM3UmxyQkVxRXpuSnBNeDJ3VkpLcVdRZHlWSWh6Q082YzRnOWN3VExGbUhkVXVURXMzdDNBN1MyNENrUkM2TE1KSFFvRTJzay1uWlJyZE9fTHVNNUJJcVp2b1dWUC1Salp4OWk4OGdaaDhvOEcyWW1xZnMwczRzYW1fam85bmFaYlo4aFBFQ0FZdnZUZ29ObzRHMGpXZERZeGdPWHlXTE80bTk1SEdMSFJMZjZ5M29vdkZad2QwN2FFbThEU3dBX3hsY1V4WHNNZ0ZlYVVVZkp2NEV4USIsICJlIjogIkFRQUIiLCAia2lkIjogInBvd2Vyc3luYyJ9 +POWERSYNC_JWKS_PRIVATE_KEY=eyJhbGciOiAiUlMyNTYiLCAia3R5IjogIlJTQSIsICJuIjogInFhdVVnb0ZXenRNcjVEYks3bFIxZXUxazJrdllyblJkRGh1NDFyWnFLeWhDWkJya0FTS0d0N25KbVUwVEpKb1d0cFF2eHVvc0ZGeW1BMUhXQnNaY0dtVlcxdlowdDJlazl4THg5bjg2UWRIVWc1MktsRG9ZUzNtRTFaWW5BYzJfRDM3UmxyQkVxRXpuSnBNeDJ3VkpLcVdRZHlWSWh6Q082YzRnOWN3VExGbUhkVXVURXMzdDNBN1MyNENrUkM2TE1KSFFvRTJzay1uWlJyZE9fTHVNNUJJcVp2b1dWUC1Salp4OWk4OGdaaDhvOEcyWW1xZnMwczRzYW1fam85bmFaYlo4aFBFQ0FZdnZUZ29ObzRHMGpXZERZeGdPWHlXTE80bTk1SEdMSFJMZjZ5M29vdkZad2QwN2FFbThEU3dBX3hsY1V4WHNNZ0ZlYVVVZkp2NEV4USIsICJlIjogIkFRQUIiLCAiZCI6ICJQZXVwNjhUakZ1RVhaQmFoRWNDT0RWcEUwNndaZkhWb0hvVjhmQk9maEhlUlh6STNJcmprZkhtWHV0UlhsNlNLaElCcFBVbHA0OVo2R2IwTWhIVncySXRDV1hvaFYydkNWdzg1Y2RHMXc1NmQxWml4b2UzZnZ1LXV6RG9icXp0WXJvR0VZTi1jZHVWMS1HeUFwZU4wYzlWdmR5UUtwNWZQbUVGTFl4amlxR3k5UUhyTldpcGJmZXdPUGY0YUl4X05VRnE3R1BsUk1yalA4VEhvSzNPOVNfXzJpR09LRVpINDFUWkpscVBZX0s5dFNkbFNKd1FPWEtwOFc2ZUdGT3l2MElueVhsUXhHb0ZBWVNrUC12WTlWQy1vTUtzdmhocm1GeGM0VlU2OUZ3VWFJYUdaOU9jaXF4M3B0aE9sU1drRjFhbEtxNWFJZ2VHbEUzM2VyNGthSXciLCAicCI6ICI1WDN0QzN4Z0hwbm91U1JwSlg4c0ZWRm5vamhxMWJoWkF3c3VRaXBxWWgtZmJNRGI4a2NTTy1fT3BEMExNekYzcHp0dVNRb0NZOFc0WjI0TEJ6cFRuUlFid0JrYWt3VDMybmZIU1J0d3RnM1ZjWkkxZFNsdHgtclhEcHlBMDNHa1RvLUxEZkp1UzF0a1FYQXB0OTBkcnJHMndjQ25oRXc4bGx2SzR2cWRucHMiLCAicSI6ICJ2VVM2V2QtY2trTUJMVmJvSkVaVnRtMlFLTFE2dV9oZEFrbTFWa3dGajMxZWZWRTlFRWRSa0F0dGVoOWh2ZzBkM2FXVDZ1bFQ4YlpubWo3WkFjNG55aVdwOTlFd0k5U0hFX01UUE11YVZSeUw5SmFIX2R0Uk5nVGE5UV9hZUs2d1pkY3RwLUZRT1lteVlDWmhzRnVOTG45TFJ3UklJOVJ0YlBXYW55X01jQjgiLCAiZHAiOiAiWjFNNkhmakN3aVJqcnJBaEV6dmQyajlMbkxNd0RzZXdjX2xkdTNhamJVaDFuQjU5S09rczRZV0lFVlJXclpieEczOWJtVkVEWUc2T0p5dFpsY2lDQ3ZBWnluVEREVHlvWjFtVWhXcndaVmQzS1dvOTNXRm94eUVKOE04d0JZTmVDZTBCRzZkeVYwVnZyekxUNWEtTmhMRUk2dFZWMXZBSU8xNWF5N1V3c0U4IiwgImRxIjogIktsclpBUWZEZUEtNmtiVGpHa3NMSDFvQmFycDZjbG93SmpUc2ViVmxnU2pqSGxReHdCVFZzZEI4M1Zsc2ZDVmZTNXlrTDJ1cnQybkVZWVl5OWU1MmhReE1yd0tITFYyQUpQeS1qMXBZM1RjWU10SUUtTkE5cWtNSDVOTjVab3hoT1VrZ0ZIT2RpbUxBSWpnMG9FeThtVzB2SVdOWjZYcS1TaVhrUmo5aUZxMCIsICJxaSI6ICJzSV84RTh0MTBsRDY2NTh3UXRpY19BaUUxOVk1Rms0SDJWbnpGclBhVU04aWFNaVc2eUZxMFZuN3RXa2RTWS1STTB1SFMwdmVmSEcyZTBKSWxEanhBUmZWZUcwNTFyVUNRZjBkSnR4U0ZDQUp2eGxMRTZsYjZOQlUwZVIyMld6bjVob1ZZTVpHZnQ5QnA0SlVOOHJkMF9lMm1kSjhxc09wM1NLQ3NTSTByUkkiLCAia2lkIjogInBvd2Vyc3luYyJ9 +POWERSYNC_URL=http://localhost:8080 + # The server's timezone, for a list of possible names: # https://en.wikipedia.org/wiki/List_of_tz_database_time_zones TIME_ZONE=Europe/Berlin @@ -107,9 +113,13 @@ DJANGO_DB_HOST=db DJANGO_DB_PORT=5432 DJANGO_PERFORM_MIGRATIONS=True # Perform any new database migrations on startup +# +# Powersync # postgres://:@:/ +# Alternative: PS_STORAGE_MONGO_URI: mongodb://mongo:27017/powersync_wger PS_PG_URI=postgres://wger:wger@db:5432/wger -PS_MONGO_URI: mongodb://mongo:27017/powersync_wger +PS_STORAGE_PG_URI=postgres://powersync_storage_user:secure_password@db:5432/wger +PS_PORT=8080 # # Cache @@ -238,8 +248,3 @@ EXPOSE_PROMETHEUS_METRICS=False #S3_MEDIA_FILES_LOCATION=media #S3_STATIC_FILES_LOCATION=static #AWS_QUERYSTRING_AUTH=False - - -# -# Powersync -PS_PORT=8080 \ No newline at end of file diff --git a/dev-postgres-powersync/config-powersync/powersync.yaml b/dev-postgres-powersync/config-powersync/powersync.yaml index 7b0008c6c..50c265925 100644 --- a/dev-postgres-powersync/config-powersync/powersync.yaml +++ b/dev-postgres-powersync/config-powersync/powersync.yaml @@ -6,9 +6,9 @@ # # Only environment variables with names starting with `PS_` can be substituted. # -# e.g. With the environment variable `export PS_MONGO_URI=mongodb://localhost:27017` +# e.g. With the environment variable `export PS_STORAGE_MONGO_URI=mongodb://localhost:27017` # and YAML code: -# uri: !env PS_MONGO_URI +# uri: !env PS_STORAGE_MONGO_URI # The YAML will resolve to: # uri: mongodb://localhost:27017 # @@ -23,7 +23,6 @@ # 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 @@ -33,15 +32,9 @@ replication: # 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 @@ -55,8 +48,11 @@ replication: # Connection settings for sync bucket storage storage: - type: mongodb - uri: !env PS_MONGO_URI + type: postgresql + uri: !env PS_STORAGE_PG_URI + sslmode: disable +# type: mongodb +# uri: !env PS_STORAGE_MONGO_URI # The port which the PowerSync API server will listen on port: !env PS_PORT @@ -67,11 +63,7 @@ sync_rules: # 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 diff --git a/dev-postgres-powersync/docker-compose.yml b/dev-postgres-powersync/docker-compose.yml index 694509d7c..f666c6319 100644 --- a/dev-postgres-powersync/docker-compose.yml +++ b/dev-postgres-powersync/docker-compose.yml @@ -70,5 +70,4 @@ networks: name: wger-dev-network include: - - path: powersync-services/mongo.yaml - path: powersync-services/powersync.yaml diff --git a/dev-postgres-powersync/powersync-services/mongo.yaml b/dev-postgres-powersync/powersync-services/mongo.yaml deleted file mode 100644 index 5c2bc8ae5..000000000 --- a/dev-postgres-powersync/powersync-services/mongo.yaml +++ /dev/null @@ -1,24 +0,0 @@ -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: diff --git a/dev-postgres-powersync/powersync-services/powersync.yaml b/dev-postgres-powersync/powersync-services/powersync.yaml index 1488b92b2..980cfbb8c 100644 --- a/dev-postgres-powersync/powersync-services/powersync.yaml +++ b/dev-postgres-powersync/powersync-services/powersync.yaml @@ -1,11 +1,12 @@ services: powersync: depends_on: - mongo: + db: condition: service_completed_successfully restart: unless-stopped image: docker.io/journeyapps/powersync-service:latest + # The unified service runs an API server and replication worker in the same container. # These services can be executed in different containers by using individual entry commands e.g. # Start only the API server with @@ -26,12 +27,27 @@ services: volumes: # Mounts the specified config folder to the container # This folder should contain `powersync.yaml and sync_rules.yaml - - ../config-powersync:/config + - ../config-powersync:/config:ro env_file: - ../../config/prod.env - ../../config/dev.env + # Tip: to run wger Django and Postgres locally on the host (instead of + # in the `web` / `db` containers) while keeping PowerSync containerised, + # override the URLs in a docker-compose.override.yml so they reach back + # to the host: + # + # services: + # powersync: + # extra_hosts: + # # Linux needs this, macOS/Windows work out of the box + # - "host.docker.internal:host-gateway" + # environment: + # PS_PG_URI: postgres://wger:wger@host.docker.internal:5432/wger + # PS_JWKS_URL: http://host.docker.internal:8000/api/v2/powersync-keys + # + environment: # This is the path (inside the container) to the YAML config file # Alternatively the config path can be specified in the command From def94f55d47622b32116af95d210439539ed57f9 Mon Sep 17 00:00:00 2001 From: Roland Geider Date: Tue, 21 Apr 2026 14:54:22 +0200 Subject: [PATCH 34/53] The pg_ivm extension is not needed anymore --- postgres/Dockerfile | 24 ------------------------ 1 file changed, 24 deletions(-) delete mode 100644 postgres/Dockerfile diff --git a/postgres/Dockerfile b/postgres/Dockerfile deleted file mode 100644 index 0a2b15e8a..000000000 --- a/postgres/Dockerfile +++ /dev/null @@ -1,24 +0,0 @@ -FROM postgres:15-bookworm AS builder - -ENV VERSION=1.12 - -RUN apt-get update && \ - apt-get install -y \ - git \ - build-essential \ - postgresql-server-dev-15 - -WORKDIR /tmp -RUN git clone -b v${VERSION} https://github.com/sraoss/pg_ivm.git - -WORKDIR /tmp/pg_ivm -RUN make - -# Create the final image -FROM postgres:15-bookworm - -COPY --from=builder /tmp/pg_ivm/pg_ivm*.sql /usr/share/postgresql/15/extension -COPY --from=builder /tmp/pg_ivm/pg_ivm.control /usr/share/postgresql/15/extension -COPY --from=builder /tmp/pg_ivm/pg_ivm.so /usr/lib/postgresql/15/lib - -EXPOSE 5432 \ No newline at end of file From 6fc34861e2fa6f9bbfd9b20f70a0578c0da29b99 Mon Sep 17 00:00:00 2001 From: Roland Geider Date: Tue, 21 Apr 2026 16:03:42 +0200 Subject: [PATCH 35/53] Refactor services and dev setup Common services can now be included instead of being duplicated on each service. Changes to volumes, etc. can still be applied as needed. --- .gitignore | 1 - dev-postgres-powersync/.env.example | 3 - dev-postgres-powersync/docker-compose.yml | 73 ------------ dev-postgres/docker-compose.yml | 50 ++++---- dev-postgres/initdb/01-reset-password.sql | 23 ++++ dev-postgres/initdb/02-cleanup.sql | 7 ++ dev-postgres/initdb/03-reduce-entries.sql | 110 ++++++++++++++++++ dev-postgres/initdb/04-powersync.sql | 9 ++ dev-postgres/initdb/README.md | 8 ++ dev/docker-compose.yml | 14 +-- docker-compose.yml | 36 +----- .../config-powersync/powersync.yaml | 0 .../config-powersync/sync_rules.yaml | 0 services/postgres.yaml | 26 +++++ .../powersync.yaml | 13 ++- services/redis.yaml | 21 ++++ 16 files changed, 239 insertions(+), 155 deletions(-) delete mode 100644 dev-postgres-powersync/.env.example delete mode 100644 dev-postgres-powersync/docker-compose.yml create mode 100644 dev-postgres/initdb/01-reset-password.sql create mode 100644 dev-postgres/initdb/02-cleanup.sql create mode 100644 dev-postgres/initdb/03-reduce-entries.sql create mode 100644 dev-postgres/initdb/04-powersync.sql create mode 100644 dev-postgres/initdb/README.md rename {dev-postgres-powersync => services}/config-powersync/powersync.yaml (100%) rename {dev-postgres-powersync => services}/config-powersync/sync_rules.yaml (100%) create mode 100644 services/postgres.yaml rename {dev-postgres-powersync/powersync-services => services}/powersync.yaml (86%) create mode 100644 services/redis.yaml diff --git a/.gitignore b/.gitignore index f75eeb768..c2de2c78d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,4 @@ /config/Caddyfile /docker-compose.override.yml /dev-postgres/.env -/dev-postgres-powersync/.env /dev/.env \ No newline at end of file diff --git a/dev-postgres-powersync/.env.example b/dev-postgres-powersync/.env.example deleted file mode 100644 index a814d23f2..000000000 --- a/dev-postgres-powersync/.env.example +++ /dev/null @@ -1,3 +0,0 @@ -# Copy to .env - -WGER_CODEPATH=/path/to/wger/server \ No newline at end of file diff --git a/dev-postgres-powersync/docker-compose.yml b/dev-postgres-powersync/docker-compose.yml deleted file mode 100644 index f666c6319..000000000 --- a/dev-postgres-powersync/docker-compose.yml +++ /dev/null @@ -1,73 +0,0 @@ -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/powersync.yaml diff --git a/dev-postgres/docker-compose.yml b/dev-postgres/docker-compose.yml index 9f32e6619..0617905a0 100644 --- a/dev-postgres/docker-compose.yml +++ b/dev-postgres/docker-compose.yml @@ -15,45 +15,35 @@ services: 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" - command: tail -f /dev/null - - cache: - image: redis - expose: - - 6379 - healthcheck: - test: redis-cli ping - interval: 10s - timeout: 5s - retries: 5 - start_period: 30s - restart: unless-stopped + # No need to persist the data in dev +# cache: +# volumes: !override +# - ../config/redis.conf:/usr/local/etc/redis/redis.conf db: - image: postgres:15-alpine - environment: - - POSTGRES_USER=wger - - POSTGRES_PASSWORD=wger - - POSTGRES_DB=wger - volumes: - - postgres-data-dev:/var/lib/postgresql/data/ + volumes: !override + - postgres-dev-data:/var/lib/postgresql/data/ + - ./initdb:/docker-entrypoint-initdb.d:ro ports: - "5432:5432" - expose: - - 5432 - healthcheck: - test: pg_isready -U wger - interval: 10s - timeout: 5s - retries: 5 - start_period: 30s - restart: unless-stopped volumes: - postgres-data-dev: + postgres-dev-data: + +networks: + default: + name: wger-dev-network + +include: + - path: ../services/postgres.yaml + - path: ../services/powersync.yaml + - path: ../services/redis.yaml diff --git a/dev-postgres/initdb/01-reset-password.sql b/dev-postgres/initdb/01-reset-password.sql new file mode 100644 index 000000000..d9d6f7b7c --- /dev/null +++ b/dev-postgres/initdb/01-reset-password.sql @@ -0,0 +1,23 @@ +BEGIN; + + +-- Set password to adminadmin +UPDATE auth_user + SET password = 'pbkdf2_sha256$1000000$Pw11yvSIktZVAx8Lcpaizx$dMqOh/9VoCkfxksY9Cm78p6LXvMrYZBoqP31z7TRCj4=' + WHERE username = 'admin'; + +-- Set tokens to known values +UPDATE authtoken_token + SET key = '73f1ee4fbc4f58bfcd777755fc36c6260823a084' + WHERE user_id = (SELECT id FROM auth_user WHERE username = 'admin'); + +UPDATE authtoken_token + SET key = '31e2ea0322c07b9df583a9b6d1e794f7139e78d4' + WHERE user_id = (SELECT id FROM auth_user WHERE username = 'user'); + +-- UPDATE core_userprofile +-- SET email_verified = true +-- WHERE id IN (SELECT id FROM auth_user WHERE username IN ('admin', 'user')); + + +COMMIT; \ No newline at end of file diff --git a/dev-postgres/initdb/02-cleanup.sql b/dev-postgres/initdb/02-cleanup.sql new file mode 100644 index 000000000..38ff10292 --- /dev/null +++ b/dev-postgres/initdb/02-cleanup.sql @@ -0,0 +1,7 @@ +BEGIN; + +TRUNCATE TABLE exercises_exerciseimage; +TRUNCATE TABLE exercises_exercisevideo; +TRUNCATE TABLE nutrition_image; + +COMMIT; \ No newline at end of file diff --git a/dev-postgres/initdb/03-reduce-entries.sql b/dev-postgres/initdb/03-reduce-entries.sql new file mode 100644 index 000000000..97c9c2bd4 --- /dev/null +++ b/dev-postgres/initdb/03-reduce-entries.sql @@ -0,0 +1,110 @@ +-- Reduce dump size for faster local migration / testing runs. +-- +-- 0) Make every FK in the DB ON DELETE CASCADE. Django's on_delete is +-- enforced in Python only — at the Postgres level every FK is NO ACTION, +-- so a raw DELETE on auth_user fails on the first child table. Since +-- auth_user cascades across ~54 tables transitively, we bulk-rewrite +-- all FKs instead of chasing the chain by hand. This is destructive +-- for a production DB (SET_NULL/PROTECT semantics are lost), but for a +-- freshly imported dump that we're about to shrink anyway it's fine. +-- +-- 1) Users: keep 'admin', 'user' and 100 random others. With step 0 in +-- place the CASCADE removes dependent rows (routines, plans, sessions, +-- logs, weight entries, images, trophies, gym contracts, simple_history +-- records, admin log, tokens, …) automatically. +-- +-- 2) Ingredients: keep every ingredient still referenced from MealItem, +-- LogItem or IngredientWeightUnit (these three are the only FKs that +-- point at nutrition_ingredient), plus enough random extras to reach +-- 100 000 rows. If more than 100 000 ingredients are referenced they +-- all stay. + +BEGIN; + +-- --------------------------------------------------------------------------- +-- 0. Rewrite every FK in the public schema to ON DELETE CASCADE +-- --------------------------------------------------------------------------- +DO $$ +DECLARE + r record; + col_list text; + ref_col_list text; +BEGIN + FOR r IN + SELECT c.conrelid::regclass AS tbl, + c.confrelid::regclass AS ref_tbl, + c.conname, + c.conkey, + c.confkey + FROM pg_constraint c + WHERE c.contype = 'f' + AND c.confdeltype <> 'c' + AND c.connamespace = 'public'::regnamespace + LOOP + SELECT string_agg(quote_ident(a.attname), ',' ORDER BY k.ord) + INTO col_list + FROM unnest(r.conkey) WITH ORDINALITY AS k(attnum, ord) + JOIN pg_attribute a ON a.attrelid = r.tbl AND a.attnum = k.attnum; + + SELECT string_agg(quote_ident(a.attname), ',' ORDER BY k.ord) + INTO ref_col_list + FROM unnest(r.confkey) WITH ORDINALITY AS k(attnum, ord) + JOIN pg_attribute a ON a.attrelid = r.ref_tbl AND a.attnum = k.attnum; + + EXECUTE format('ALTER TABLE %s DROP CONSTRAINT %I', + r.tbl, r.conname); + EXECUTE format( + 'ALTER TABLE %s ADD CONSTRAINT %I FOREIGN KEY (%s) ' + 'REFERENCES %s(%s) ON DELETE CASCADE', + r.tbl, r.conname, col_list, r.ref_tbl, ref_col_list); + END LOOP; +END $$; + +-- --------------------------------------------------------------------------- +-- 1. Users +-- --------------------------------------------------------------------------- +WITH users_to_keep AS ( + SELECT id FROM auth_user WHERE username IN ('admin', 'user') + UNION + (SELECT id + FROM auth_user + WHERE username NOT IN ('admin', 'user') + ORDER BY random() + LIMIT 100) +) +DELETE FROM auth_user +WHERE id NOT IN (SELECT id FROM users_to_keep); + +-- --------------------------------------------------------------------------- +-- 2. Ingredients +-- --------------------------------------------------------------------------- +-- Note: user deletion above already cascaded and removed a lot of MealItem / +-- LogItem rows, so the "referenced" set is evaluated against the *reduced* +-- state — which is what we want. +WITH referenced AS ( + SELECT ingredient_id AS id FROM nutrition_mealitem + UNION + SELECT ingredient_id FROM nutrition_logitem + UNION + SELECT ingredient_id FROM nutrition_ingredientweightunit +), +random_extras AS ( + SELECT id + FROM nutrition_ingredient + WHERE id NOT IN (SELECT id FROM referenced) + ORDER BY random() + LIMIT GREATEST(0, 100000 - (SELECT count(*) FROM referenced)) +), +ingredients_to_keep AS ( + SELECT id FROM referenced + UNION + SELECT id FROM random_extras +) +DELETE FROM nutrition_ingredient +WHERE id NOT IN (SELECT id FROM ingredients_to_keep); + +COMMIT; + +-- Reclaim space and refresh planner stats. Must run outside the transaction. +VACUUM ANALYZE auth_user; +VACUUM ANALYZE nutrition_ingredient; diff --git a/dev-postgres/initdb/04-powersync.sql b/dev-postgres/initdb/04-powersync.sql new file mode 100644 index 000000000..3818bd095 --- /dev/null +++ b/dev-postgres/initdb/04-powersync.sql @@ -0,0 +1,9 @@ +-- Creates a dedicated user and schema for PowerSync's bucket storage, +-- living inside the wger database (separate schema, no separate DB needed). +-- https://docs.powersync.com/configuration/powersync-service/self-hosted-instances#postgres-storage + +CREATE USER powersync_storage_user WITH PASSWORD 'secure_password'; +CREATE SCHEMA IF NOT EXISTS powersync AUTHORIZATION powersync_storage_user; +GRANT CONNECT ON DATABASE wger TO powersync_storage_user; +GRANT USAGE ON SCHEMA powersync TO powersync_storage_user; +GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA powersync TO powersync_storage_user; \ No newline at end of file diff --git a/dev-postgres/initdb/README.md b/dev-postgres/initdb/README.md new file mode 100644 index 000000000..425e47e9a --- /dev/null +++ b/dev-postgres/initdb/README.md @@ -0,0 +1,8 @@ +# Postgres init scripts + +This folder contains some SQL scripts that are applied by postgres **once**, on +the very first start against an empty data volume. + +They run some initialisation tasks, such as trimming the db and resetting passwords. +Note that the files are run by postgres in alphabetical order. If you want to skip +a file, just rename it to have a non-recognised extension (e.g. `.txt`). diff --git a/dev/docker-compose.yml b/dev/docker-compose.yml index 2ea704140..c1e55ebb5 100644 --- a/dev/docker-compose.yml +++ b/dev/docker-compose.yml @@ -22,16 +22,8 @@ services: ports: - "8000:8000" + # So this never exists command: tail -f /dev/null - cache: - image: redis - expose: - - 6379 - healthcheck: - test: redis-cli ping - interval: 10s - timeout: 5s - retries: 5 - start_period: 30s - restart: unless-stopped +include: + - path: ../services/redis.yaml \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index 075aa3245..b2df48fad 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -52,49 +52,17 @@ services: restart: unless-stopped db: - image: docker.io/postgres:15-alpine environment: - - POSTGRES_USER=wger - - POSTGRES_PASSWORD=wger - - POSTGRES_DB=wger - TZ=Europe/Berlin - volumes: - - postgres-data:/var/lib/postgresql/data/ - expose: - - 5432 logging: driver: json-file options: max-size: 5m max-file: 5 - healthcheck: - test: ["CMD", "pg_isready", "-U", "wger" ] - interval: 10s - timeout: 5s - retries: 5 - start_period: 30s - restart: unless-stopped cache: - image: docker.io/redis - expose: - - 6379 - logging: - driver: json-file - options: - max-size: 5m - max-file: 5 volumes: - - ./config/redis.conf:/usr/local/etc/redis/redis.conf - redis-data:/data - command: ["redis-server", "/usr/local/etc/redis/redis.conf"] - healthcheck: - test: redis-cli ping - interval: 10s - timeout: 5s - retries: 5 - start_period: 30s - restart: unless-stopped # You probably want to limit the memory usage of the cache, otherwise it might # hog all the available memory. Remove or change according to your needs. @@ -156,3 +124,7 @@ volumes: networks: default: name: wger_network + +include: + - path: ./services/postgres.yaml + - path: ./services/powersync.yaml \ No newline at end of file diff --git a/dev-postgres-powersync/config-powersync/powersync.yaml b/services/config-powersync/powersync.yaml similarity index 100% rename from dev-postgres-powersync/config-powersync/powersync.yaml rename to services/config-powersync/powersync.yaml diff --git a/dev-postgres-powersync/config-powersync/sync_rules.yaml b/services/config-powersync/sync_rules.yaml similarity index 100% rename from dev-postgres-powersync/config-powersync/sync_rules.yaml rename to services/config-powersync/sync_rules.yaml diff --git a/services/postgres.yaml b/services/postgres.yaml new file mode 100644 index 000000000..2528122e9 --- /dev/null +++ b/services/postgres.yaml @@ -0,0 +1,26 @@ +services: + db: + image: docker.io/postgres:15-alpine + environment: + - POSTGRES_USER=wger + - POSTGRES_PASSWORD=wger + - POSTGRES_DB=wger + - TZ=Europe/Berlin + logging: + driver: json-file + options: + max-size: 5m + max-file: 5 + volumes: + - postgres-data:/var/lib/postgresql/data/ + 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 diff --git a/dev-postgres-powersync/powersync-services/powersync.yaml b/services/powersync.yaml similarity index 86% rename from dev-postgres-powersync/powersync-services/powersync.yaml rename to services/powersync.yaml index 980cfbb8c..35adf8a3e 100644 --- a/dev-postgres-powersync/powersync-services/powersync.yaml +++ b/services/powersync.yaml @@ -25,13 +25,16 @@ services: command: ["start", "-r", "unified"] volumes: - # Mounts the specified config folder to the container - # This folder should contain `powersync.yaml and sync_rules.yaml - - ../config-powersync:/config:ro + # Mounts the PowerSync config folder (powersync.yaml + sync_rules.yaml). + # Paths in an `include:`d file are resolved relative to *this* file, + # not to the including docker-compose.yml. Production setups that want + # their own config can override this mount via `volumes: !override` + # in their compose file. + - ./config-powersync:/config:ro env_file: - - ../../config/prod.env - - ../../config/dev.env + - ../config/prod.env + - ../config/dev.env # Tip: to run wger Django and Postgres locally on the host (instead of # in the `web` / `db` containers) while keeping PowerSync containerised, diff --git a/services/redis.yaml b/services/redis.yaml new file mode 100644 index 000000000..2bbb11e55 --- /dev/null +++ b/services/redis.yaml @@ -0,0 +1,21 @@ +services: + cache: + image: docker.io/redis + expose: + - 6379 + logging: + driver: json-file + options: + max-size: 5m + max-file: 5 + volumes: + - ../config/redis.conf:/usr/local/etc/redis/redis.conf +# - redis-data:/data + command: [ "redis-server", "/usr/local/etc/redis/redis.conf" ] + healthcheck: + test: redis-cli ping + interval: 10s + timeout: 5s + retries: 5 + start_period: 30s + restart: unless-stopped From 3a1fc4a84969e6e5a9a6819035bb9a3dd7726d73 Mon Sep 17 00:00:00 2001 From: Roland Geider Date: Wed, 22 Apr 2026 11:54:08 +0200 Subject: [PATCH 36/53] Put powersync behind the reverse proxy as well This saves us the trouble of having to expose the PS service by itself and makes updating instances much easier. --- config/Caddyfile.example | 24 +++++++++++++++--------- config/dev.env | 2 +- config/nginx.conf | 27 +++++++++++++++++++++++++++ config/prod.env | 25 +++++++++++++++++++------ dev-postgres/docker-compose.yml | 10 ++++++++++ docker-compose.yml | 12 +++++++++++- services/powersync.yaml | 17 +---------------- 7 files changed, 84 insertions(+), 33 deletions(-) diff --git a/config/Caddyfile.example b/config/Caddyfile.example index a103df65c..88198fee6 100644 --- a/config/Caddyfile.example +++ b/config/Caddyfile.example @@ -33,15 +33,6 @@ localhost { encode - # or "reverse_proxy anubis:3000 {" if you are using Anubis - reverse_proxy web:8000 { - header_up Host {host} - header_up X-Real-IP {remote_host} - header_up X-Forwarded-For {http.X-Forwarded-For} {remote_host} - header_up X-Forwarded-Proto {scheme} - header_up X-Http-Version {http.request.proto} - } - handle /static/* { root * /wger @@ -56,6 +47,21 @@ localhost { root * /wger file_server } + + # Reverse proxy for the PowerSync service, used by the mobile app for offline mode. + handle_path /ps/* { + reverse_proxy powersync:8080 + } + + # Catch-all: everything not matched above goes to the wger backend. + # Replace with `reverse_proxy anubis:3000` if you are using Anubis. + reverse_proxy web:8000 { + header_up Host {host} + header_up X-Real-IP {remote_host} + header_up X-Forwarded-For {http.X-Forwarded-For} {remote_host} + header_up X-Forwarded-Proto {scheme} + header_up X-Http-Version {http.request.proto} + } } # Refer to the Caddy docs for more information: diff --git a/config/dev.env b/config/dev.env index 8a6c49366..573c4dd94 100644 --- a/config/dev.env +++ b/config/dev.env @@ -12,7 +12,7 @@ DJANGO_STORAGES_STATICFILES_BACKEND=django.contrib.staticfiles.storage.StaticFil # These can be generated with docker compose exec web ./manage.py generate-powersync-keys #POWERSYNC_JWKS_PUBLIC_KEY=eyJhbGciOiAiUlMyNTYiLCAia3R5IjogIlJTQSIsICJuIjogInFhdVVnb0ZXenRNcjVEYks3bFIxZXUxazJrdllyblJkRGh1NDFyWnFLeWhDWkJya0FTS0d0N25KbVUwVEpKb1d0cFF2eHVvc0ZGeW1BMUhXQnNaY0dtVlcxdlowdDJlazl4THg5bjg2UWRIVWc1MktsRG9ZUzNtRTFaWW5BYzJfRDM3UmxyQkVxRXpuSnBNeDJ3VkpLcVdRZHlWSWh6Q082YzRnOWN3VExGbUhkVXVURXMzdDNBN1MyNENrUkM2TE1KSFFvRTJzay1uWlJyZE9fTHVNNUJJcVp2b1dWUC1Salp4OWk4OGdaaDhvOEcyWW1xZnMwczRzYW1fam85bmFaYlo4aFBFQ0FZdnZUZ29ObzRHMGpXZERZeGdPWHlXTE80bTk1SEdMSFJMZjZ5M29vdkZad2QwN2FFbThEU3dBX3hsY1V4WHNNZ0ZlYVVVZkp2NEV4USIsICJlIjogIkFRQUIiLCAia2lkIjogInBvd2Vyc3luYyJ9 #POWERSYNC_JWKS_PRIVATE_KEY=eyJhbGciOiAiUlMyNTYiLCAia3R5IjogIlJTQSIsICJuIjogInFhdVVnb0ZXenRNcjVEYks3bFIxZXUxazJrdllyblJkRGh1NDFyWnFLeWhDWkJya0FTS0d0N25KbVUwVEpKb1d0cFF2eHVvc0ZGeW1BMUhXQnNaY0dtVlcxdlowdDJlazl4THg5bjg2UWRIVWc1MktsRG9ZUzNtRTFaWW5BYzJfRDM3UmxyQkVxRXpuSnBNeDJ3VkpLcVdRZHlWSWh6Q082YzRnOWN3VExGbUhkVXVURXMzdDNBN1MyNENrUkM2TE1KSFFvRTJzay1uWlJyZE9fTHVNNUJJcVp2b1dWUC1Salp4OWk4OGdaaDhvOEcyWW1xZnMwczRzYW1fam85bmFaYlo4aFBFQ0FZdnZUZ29ObzRHMGpXZERZeGdPWHlXTE80bTk1SEdMSFJMZjZ5M29vdkZad2QwN2FFbThEU3dBX3hsY1V4WHNNZ0ZlYVVVZkp2NEV4USIsICJlIjogIkFRQUIiLCAiZCI6ICJQZXVwNjhUakZ1RVhaQmFoRWNDT0RWcEUwNndaZkhWb0hvVjhmQk9maEhlUlh6STNJcmprZkhtWHV0UlhsNlNLaElCcFBVbHA0OVo2R2IwTWhIVncySXRDV1hvaFYydkNWdzg1Y2RHMXc1NmQxWml4b2UzZnZ1LXV6RG9icXp0WXJvR0VZTi1jZHVWMS1HeUFwZU4wYzlWdmR5UUtwNWZQbUVGTFl4amlxR3k5UUhyTldpcGJmZXdPUGY0YUl4X05VRnE3R1BsUk1yalA4VEhvSzNPOVNfXzJpR09LRVpINDFUWkpscVBZX0s5dFNkbFNKd1FPWEtwOFc2ZUdGT3l2MElueVhsUXhHb0ZBWVNrUC12WTlWQy1vTUtzdmhocm1GeGM0VlU2OUZ3VWFJYUdaOU9jaXF4M3B0aE9sU1drRjFhbEtxNWFJZ2VHbEUzM2VyNGthSXciLCAicCI6ICI1WDN0QzN4Z0hwbm91U1JwSlg4c0ZWRm5vamhxMWJoWkF3c3VRaXBxWWgtZmJNRGI4a2NTTy1fT3BEMExNekYzcHp0dVNRb0NZOFc0WjI0TEJ6cFRuUlFid0JrYWt3VDMybmZIU1J0d3RnM1ZjWkkxZFNsdHgtclhEcHlBMDNHa1RvLUxEZkp1UzF0a1FYQXB0OTBkcnJHMndjQ25oRXc4bGx2SzR2cWRucHMiLCAicSI6ICJ2VVM2V2QtY2trTUJMVmJvSkVaVnRtMlFLTFE2dV9oZEFrbTFWa3dGajMxZWZWRTlFRWRSa0F0dGVoOWh2ZzBkM2FXVDZ1bFQ4YlpubWo3WkFjNG55aVdwOTlFd0k5U0hFX01UUE11YVZSeUw5SmFIX2R0Uk5nVGE5UV9hZUs2d1pkY3RwLUZRT1lteVlDWmhzRnVOTG45TFJ3UklJOVJ0YlBXYW55X01jQjgiLCAiZHAiOiAiWjFNNkhmakN3aVJqcnJBaEV6dmQyajlMbkxNd0RzZXdjX2xkdTNhamJVaDFuQjU5S09rczRZV0lFVlJXclpieEczOWJtVkVEWUc2T0p5dFpsY2lDQ3ZBWnluVEREVHlvWjFtVWhXcndaVmQzS1dvOTNXRm94eUVKOE04d0JZTmVDZTBCRzZkeVYwVnZyekxUNWEtTmhMRUk2dFZWMXZBSU8xNWF5N1V3c0U4IiwgImRxIjogIktsclpBUWZEZUEtNmtiVGpHa3NMSDFvQmFycDZjbG93SmpUc2ViVmxnU2pqSGxReHdCVFZzZEI4M1Zsc2ZDVmZTNXlrTDJ1cnQybkVZWVl5OWU1MmhReE1yd0tITFYyQUpQeS1qMXBZM1RjWU10SUUtTkE5cWtNSDVOTjVab3hoT1VrZ0ZIT2RpbUxBSWpnMG9FeThtVzB2SVdOWjZYcS1TaVhrUmo5aUZxMCIsICJxaSI6ICJzSV84RTh0MTBsRDY2NTh3UXRpY19BaUUxOVk1Rms0SDJWbnpGclBhVU04aWFNaVc2eUZxMFZuN3RXa2RTWS1STTB1SFMwdmVmSEcyZTBKSWxEanhBUmZWZUcwNTFyVUNRZjBkSnR4U0ZDQUp2eGxMRTZsYjZOQlUwZVIyMld6bjVob1ZZTVpHZnQ5QnA0SlVOOHJkMF9lMm1kSjhxc09wM1NLQ3NTSTByUkkiLCAia2lkIjogInBvd2Vyc3luYyJ9 -#POWERSYNC_URL=http://localhost:8080 +POWERSYNC_URL=http://localhost:8080 #POWERSYNC_URL=http://10.0.2.2:8080 # When developing on the android emulator SECRET_KEY='dev1-docker-supersecret-key-1234567890!@#$%^&*(-_)+=' diff --git a/config/nginx.conf b/config/nginx.conf index 40456cebc..0e1a7074f 100644 --- a/config/nginx.conf +++ b/config/nginx.conf @@ -2,6 +2,12 @@ upstream wger { server web:8000; } +# Used by the /ps/ proxy below. The nginx service's `depends_on:` lists +# `powersync` so it is started before nginx tries to resolve this hostname. +upstream powersync { + server powersync:8080; +} + # Universal X-Forwarded-Proto handling for all deployment scenarios # - Uses upstream value when behind reverse proxy (Traefik, Caddy, etc.) # - Falls back to nginx's scheme for direct connections and port forwarding @@ -36,6 +42,27 @@ server { proxy_send_timeout 86400s; } + # Reverse proxy for the PowerSync service, used by the mobile app for offline mode + location /ps/ { + proxy_pass http://powersync/; + + proxy_set_header Host $http_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 $final_forwarded_proto; + + # WebSocket upgrade (used by the diagnostics app and the Web SDK) + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + + # Sync streams are long-lived (HTTP/2 streaming POST) and must not + # be buffered or cut off by short timeouts. + proxy_buffering off; + proxy_read_timeout 1d; + proxy_send_timeout 1d; + } + location /static/ { alias /wger/static/; diff --git a/config/prod.env b/config/prod.env index 25258a5af..1d78560f4 100644 --- a/config/prod.env +++ b/config/prod.env @@ -1,3 +1,7 @@ +# +# Change these settings +# + # Django's secret keys, change to a 50 character random string. Generate e.g. with: # * python -c "import secrets; print(secrets.token_urlsafe(50))" or # * https://djecrety.ir/ @@ -9,17 +13,31 @@ SECRET_KEY=wger-docker-supersecret-key-1234567890!@#$%^&*(-_) # Signing key used for JWT, use something different than the secret key SIGNING_KEY=wger-docker-secret-jwtkey-1234567890!@#$%^&*(-_=+) +# The URL where the application will be available. +SITE_URL=http://localhost + # Powersync JWT keys, used by the mobile app. This default NEEDS to be changed. # New keys can be generated with: docker compose exec web ./manage.py generate-powersync-keys POWERSYNC_JWKS_PUBLIC_KEY=eyJhbGciOiAiUlMyNTYiLCAia3R5IjogIlJTQSIsICJuIjogInFhdVVnb0ZXenRNcjVEYks3bFIxZXUxazJrdllyblJkRGh1NDFyWnFLeWhDWkJya0FTS0d0N25KbVUwVEpKb1d0cFF2eHVvc0ZGeW1BMUhXQnNaY0dtVlcxdlowdDJlazl4THg5bjg2UWRIVWc1MktsRG9ZUzNtRTFaWW5BYzJfRDM3UmxyQkVxRXpuSnBNeDJ3VkpLcVdRZHlWSWh6Q082YzRnOWN3VExGbUhkVXVURXMzdDNBN1MyNENrUkM2TE1KSFFvRTJzay1uWlJyZE9fTHVNNUJJcVp2b1dWUC1Salp4OWk4OGdaaDhvOEcyWW1xZnMwczRzYW1fam85bmFaYlo4aFBFQ0FZdnZUZ29ObzRHMGpXZERZeGdPWHlXTE80bTk1SEdMSFJMZjZ5M29vdkZad2QwN2FFbThEU3dBX3hsY1V4WHNNZ0ZlYVVVZkp2NEV4USIsICJlIjogIkFRQUIiLCAia2lkIjogInBvd2Vyc3luYyJ9 POWERSYNC_JWKS_PRIVATE_KEY=eyJhbGciOiAiUlMyNTYiLCAia3R5IjogIlJTQSIsICJuIjogInFhdVVnb0ZXenRNcjVEYks3bFIxZXUxazJrdllyblJkRGh1NDFyWnFLeWhDWkJya0FTS0d0N25KbVUwVEpKb1d0cFF2eHVvc0ZGeW1BMUhXQnNaY0dtVlcxdlowdDJlazl4THg5bjg2UWRIVWc1MktsRG9ZUzNtRTFaWW5BYzJfRDM3UmxyQkVxRXpuSnBNeDJ3VkpLcVdRZHlWSWh6Q082YzRnOWN3VExGbUhkVXVURXMzdDNBN1MyNENrUkM2TE1KSFFvRTJzay1uWlJyZE9fTHVNNUJJcVp2b1dWUC1Salp4OWk4OGdaaDhvOEcyWW1xZnMwczRzYW1fam85bmFaYlo4aFBFQ0FZdnZUZ29ObzRHMGpXZERZeGdPWHlXTE80bTk1SEdMSFJMZjZ5M29vdkZad2QwN2FFbThEU3dBX3hsY1V4WHNNZ0ZlYVVVZkp2NEV4USIsICJlIjogIkFRQUIiLCAiZCI6ICJQZXVwNjhUakZ1RVhaQmFoRWNDT0RWcEUwNndaZkhWb0hvVjhmQk9maEhlUlh6STNJcmprZkhtWHV0UlhsNlNLaElCcFBVbHA0OVo2R2IwTWhIVncySXRDV1hvaFYydkNWdzg1Y2RHMXc1NmQxWml4b2UzZnZ1LXV6RG9icXp0WXJvR0VZTi1jZHVWMS1HeUFwZU4wYzlWdmR5UUtwNWZQbUVGTFl4amlxR3k5UUhyTldpcGJmZXdPUGY0YUl4X05VRnE3R1BsUk1yalA4VEhvSzNPOVNfXzJpR09LRVpINDFUWkpscVBZX0s5dFNkbFNKd1FPWEtwOFc2ZUdGT3l2MElueVhsUXhHb0ZBWVNrUC12WTlWQy1vTUtzdmhocm1GeGM0VlU2OUZ3VWFJYUdaOU9jaXF4M3B0aE9sU1drRjFhbEtxNWFJZ2VHbEUzM2VyNGthSXciLCAicCI6ICI1WDN0QzN4Z0hwbm91U1JwSlg4c0ZWRm5vamhxMWJoWkF3c3VRaXBxWWgtZmJNRGI4a2NTTy1fT3BEMExNekYzcHp0dVNRb0NZOFc0WjI0TEJ6cFRuUlFid0JrYWt3VDMybmZIU1J0d3RnM1ZjWkkxZFNsdHgtclhEcHlBMDNHa1RvLUxEZkp1UzF0a1FYQXB0OTBkcnJHMndjQ25oRXc4bGx2SzR2cWRucHMiLCAicSI6ICJ2VVM2V2QtY2trTUJMVmJvSkVaVnRtMlFLTFE2dV9oZEFrbTFWa3dGajMxZWZWRTlFRWRSa0F0dGVoOWh2ZzBkM2FXVDZ1bFQ4YlpubWo3WkFjNG55aVdwOTlFd0k5U0hFX01UUE11YVZSeUw5SmFIX2R0Uk5nVGE5UV9hZUs2d1pkY3RwLUZRT1lteVlDWmhzRnVOTG45TFJ3UklJOVJ0YlBXYW55X01jQjgiLCAiZHAiOiAiWjFNNkhmakN3aVJqcnJBaEV6dmQyajlMbkxNd0RzZXdjX2xkdTNhamJVaDFuQjU5S09rczRZV0lFVlJXclpieEczOWJtVkVEWUc2T0p5dFpsY2lDQ3ZBWnluVEREVHlvWjFtVWhXcndaVmQzS1dvOTNXRm94eUVKOE04d0JZTmVDZTBCRzZkeVYwVnZyekxUNWEtTmhMRUk2dFZWMXZBSU8xNWF5N1V3c0U4IiwgImRxIjogIktsclpBUWZEZUEtNmtiVGpHa3NMSDFvQmFycDZjbG93SmpUc2ViVmxnU2pqSGxReHdCVFZzZEI4M1Zsc2ZDVmZTNXlrTDJ1cnQybkVZWVl5OWU1MmhReE1yd0tITFYyQUpQeS1qMXBZM1RjWU10SUUtTkE5cWtNSDVOTjVab3hoT1VrZ0ZIT2RpbUxBSWpnMG9FeThtVzB2SVdOWjZYcS1TaVhrUmo5aUZxMCIsICJxaSI6ICJzSV84RTh0MTBsRDY2NTh3UXRpY19BaUUxOVk1Rms0SDJWbnpGclBhVU04aWFNaVc2eUZxMFZuN3RXa2RTWS1STTB1SFMwdmVmSEcyZTBKSWxEanhBUmZWZUcwNTFyVUNRZjBkSnR4U0ZDQUp2eGxMRTZsYjZOQlUwZVIyMld6bjVob1ZZTVpHZnQ5QnA0SlVOOHJkMF9lMm1kSjhxc09wM1NLQ3NTSTByUkkiLCAia2lkIjogInBvd2Vyc3luYyJ9 -POWERSYNC_URL=http://localhost:8080 # The server's timezone, for a list of possible names: # https://en.wikipedia.org/wiki/List_of_tz_database_time_zones TIME_ZONE=Europe/Berlin TZ=Europe/Berlin +# +# These settings usually don't need changing +# + + +# +# Other powersync settings +POWERSYNC_URL_PATH='ps' +# The full url for the powersync service, overrides POWERSYNC_URL_PATH. Only set if you +# know what you are doing and have a very different setup +#POWERSYNC_URL=http://ps.localhost + # # If you get CSRF errors set your domain here # Consult the docs for more details: @@ -37,10 +55,6 @@ TZ=Europe/Berlin # MEDIA_URL=https://your-domain.example.com/media/ # STATIC_URL=https://your-domain.example.com/static/ -# -# These settings usually don't need changing -# - # # Application WGER_INSTANCE=https://wger.de # Wger instance from which to sync exercises, images, etc. @@ -149,7 +163,6 @@ AXES_IPWARE_META_PRECEDENCE_ORDER=HTTP_X_FORWARDED_FOR,REMOTE_ADDR 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 # diff --git a/dev-postgres/docker-compose.yml b/dev-postgres/docker-compose.yml index 0617905a0..b4c8d2be2 100644 --- a/dev-postgres/docker-compose.yml +++ b/dev-postgres/docker-compose.yml @@ -2,6 +2,7 @@ name: wger-dev-postgres services: web: + profiles: [disabled] build: pull: true context: ${WGER_CODEPATH:?set the absolute path to the wger backend code in the .env file or env variable} @@ -30,12 +31,21 @@ services: # - ../config/redis.conf:/usr/local/etc/redis/redis.conf db: + shm_size: 256mb volumes: !override - postgres-dev-data:/var/lib/postgresql/data/ - ./initdb:/docker-entrypoint-initdb.d:ro ports: - "5432:5432" +# To run the backend "locally" on the host while keeping PowerSync and postgres containerised: +# powersync: +# # Linux needs this, macOS/Windows work out of the box +# extra_hosts: +# - "host.docker.internal:host-gateway" +# environment: +# PS_JWKS_URL: http://host.docker.internal:8000/api/v2/powersync-keys + volumes: postgres-dev-data: diff --git a/docker-compose.yml b/docker-compose.yml index b2df48fad..4a9add5f7 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -33,10 +33,18 @@ services: retries: 5 restart: unless-stopped + powersync: + depends_on: + db: + condition: service_healthy + web: + condition: service_healthy + nginx: image: docker.io/nginx:stable depends_on: - web + - powersync volumes: - ./config/nginx.conf:/etc/nginx/conf.d/default.conf - static:/wger/static:ro @@ -52,6 +60,7 @@ services: restart: unless-stopped db: + shm_size: 256mb environment: - TZ=Europe/Berlin logging: @@ -127,4 +136,5 @@ networks: include: - path: ./services/postgres.yaml - - path: ./services/powersync.yaml \ No newline at end of file + - path: ./services/powersync.yaml + - path: ./services/redis.yaml \ No newline at end of file diff --git a/services/powersync.yaml b/services/powersync.yaml index 35adf8a3e..63a74cb52 100644 --- a/services/powersync.yaml +++ b/services/powersync.yaml @@ -2,7 +2,7 @@ services: powersync: depends_on: db: - condition: service_completed_successfully + condition: service_healthy restart: unless-stopped image: docker.io/journeyapps/powersync-service:latest @@ -36,21 +36,6 @@ services: - ../config/prod.env - ../config/dev.env - # Tip: to run wger Django and Postgres locally on the host (instead of - # in the `web` / `db` containers) while keeping PowerSync containerised, - # override the URLs in a docker-compose.override.yml so they reach back - # to the host: - # - # services: - # powersync: - # extra_hosts: - # # Linux needs this, macOS/Windows work out of the box - # - "host.docker.internal:host-gateway" - # environment: - # PS_PG_URI: postgres://wger:wger@host.docker.internal:5432/wger - # PS_JWKS_URL: http://host.docker.internal:8000/api/v2/powersync-keys - # - environment: # This is the path (inside the container) to the YAML config file # Alternatively the config path can be specified in the command From cdef36153e4587e129baca3dfc4b0c83c4f59fcc Mon Sep 17 00:00:00 2001 From: Roland Geider Date: Wed, 22 Apr 2026 12:36:13 +0200 Subject: [PATCH 37/53] Collect powersync metrics in prometheus / grafana --- grafana/dashboards/powersync.json | 175 +++++++++++++++++++++++ grafana/prometheus.yml | 6 + services/config-powersync/powersync.yaml | 3 + services/powersync.yaml | 4 + 4 files changed, 188 insertions(+) create mode 100644 grafana/dashboards/powersync.json diff --git a/grafana/dashboards/powersync.json b/grafana/dashboards/powersync.json new file mode 100644 index 000000000..00186b599 --- /dev/null +++ b/grafana/dashboards/powersync.json @@ -0,0 +1,175 @@ +{ + "annotations": { "list": [] }, + "description": "Core PowerSync service metrics (replication lag, sync throughput, storage). See docs/production/offline.rst for setup. Metric source: telemetry.prometheus_port in PowerSync's powersync.yaml, scraped by prometheus.yml job 'powersync'.", + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 1, + "links": [], + "liveNow": false, + "panels": [ + { + "type": "stat", + "title": "Replication lag", + "gridPos": { "x": 0, "y": 0, "w": 6, "h": 4 }, + "datasource": { "type": "prometheus", "uid": "$datasource" }, + "targets": [ + { "expr": "powersync_replication_lag_seconds", "refId": "A", "legendFormat": "lag" } + ], + "fieldConfig": { + "defaults": { + "unit": "s", + "thresholds": { + "mode": "absolute", + "steps": [ + { "color": "green", "value": null }, + { "color": "yellow", "value": 10 }, + { "color": "red", "value": 60 } + ] + } + } + }, + "options": { "colorMode": "background", "graphMode": "area" } + }, + { + "type": "stat", + "title": "Concurrent client connections", + "gridPos": { "x": 6, "y": 0, "w": 6, "h": 4 }, + "datasource": { "type": "prometheus", "uid": "$datasource" }, + "targets": [ + { "expr": "powersync_concurrent_connections", "refId": "A" } + ], + "fieldConfig": { "defaults": { "unit": "short" } }, + "options": { "colorMode": "value", "graphMode": "area" } + }, + { + "type": "stat", + "title": "Total storage used", + "gridPos": { "x": 12, "y": 0, "w": 6, "h": 4 }, + "datasource": { "type": "prometheus", "uid": "$datasource" }, + "targets": [ + { + "expr": "powersync_replication_storage_size_bytes + powersync_operation_storage_size_bytes + powersync_parameter_storage_size_bytes", + "refId": "A", + "legendFormat": "total" + } + ], + "fieldConfig": { "defaults": { "unit": "bytes" } }, + "options": { "colorMode": "value", "graphMode": "area" } + }, + { + "type": "stat", + "title": "Operations synced (rate, 5m)", + "gridPos": { "x": 18, "y": 0, "w": 6, "h": 4 }, + "datasource": { "type": "prometheus", "uid": "$datasource" }, + "targets": [ + { "expr": "rate(powersync_operations_synced_total[5m])", "refId": "A" } + ], + "fieldConfig": { "defaults": { "unit": "ops" } }, + "options": { "colorMode": "value", "graphMode": "area" } + }, + { + "type": "timeseries", + "title": "Sync to clients — throughput", + "gridPos": { "x": 0, "y": 4, "w": 12, "h": 8 }, + "datasource": { "type": "prometheus", "uid": "$datasource" }, + "targets": [ + { + "expr": "rate(powersync_data_synced_bytes_total[1m])", + "refId": "A", + "legendFormat": "uncompressed bytes/s" + }, + { + "expr": "rate(powersync_data_sent_bytes_total[1m])", + "refId": "B", + "legendFormat": "on-wire bytes/s (compressed)" + } + ], + "fieldConfig": { + "defaults": { "unit": "Bps", "custom": { "drawStyle": "line", "lineWidth": 2, "fillOpacity": 10 } } + } + }, + { + "type": "timeseries", + "title": "Replication from source — throughput", + "gridPos": { "x": 12, "y": 4, "w": 12, "h": 8 }, + "datasource": { "type": "prometheus", "uid": "$datasource" }, + "targets": [ + { + "expr": "rate(powersync_data_replicated_bytes_total[1m])", + "refId": "A", + "legendFormat": "bytes/s" + }, + { + "expr": "rate(powersync_rows_replicated_total[1m])", + "refId": "B", + "legendFormat": "rows/s" + }, + { + "expr": "rate(powersync_transactions_replicated_total[1m])", + "refId": "C", + "legendFormat": "txs/s" + } + ], + "fieldConfig": { + "defaults": { "custom": { "drawStyle": "line", "lineWidth": 2, "fillOpacity": 10 } } + } + }, + { + "type": "timeseries", + "title": "Storage growth by type", + "gridPos": { "x": 0, "y": 12, "w": 24, "h": 8 }, + "datasource": { "type": "prometheus", "uid": "$datasource" }, + "targets": [ + { + "expr": "powersync_replication_storage_size_bytes", + "refId": "A", + "legendFormat": "replication" + }, + { + "expr": "powersync_operation_storage_size_bytes", + "refId": "B", + "legendFormat": "operations (bucket_data)" + }, + { + "expr": "powersync_parameter_storage_size_bytes", + "refId": "C", + "legendFormat": "parameters" + } + ], + "fieldConfig": { + "defaults": { + "unit": "bytes", + "custom": { "drawStyle": "line", "lineWidth": 2, "fillOpacity": 30, "stacking": { "mode": "normal" } } + } + } + } + ], + "refresh": "30s", + "schemaVersion": 39, + "tags": ["powersync", "wger"], + "templating": { + "list": [ + { + "current": { "selected": false, "text": "Prometheus", "value": "Prometheus" }, + "hide": 0, + "includeAll": false, + "label": "Datasource", + "multi": false, + "name": "datasource", + "options": [], + "query": "prometheus", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "type": "datasource" + } + ] + }, + "time": { "from": "now-1h", "to": "now" }, + "timepicker": {}, + "timezone": "", + "title": "PowerSync", + "uid": "powersync", + "version": 1, + "weekStart": "" +} diff --git a/grafana/prometheus.yml b/grafana/prometheus.yml index e3a21c014..41e3903c3 100644 --- a/grafana/prometheus.yml +++ b/grafana/prometheus.yml @@ -19,6 +19,12 @@ scrape_configs: static_configs: - targets: ['web:8000'] + # PowerSync exposes metrics on its own dedicated port (telemetry.prometheus_port + # in config-powersync/powersync.yaml), not on the 8080 sync API port. + - job_name: powersync + static_configs: + - targets: ['powersync:9090'] + - job_name: 'node-exporter' # Override the global default and scrape targets from this job every 5 seconds. diff --git a/services/config-powersync/powersync.yaml b/services/config-powersync/powersync.yaml index 50c265925..6e9fb75be 100644 --- a/services/config-powersync/powersync.yaml +++ b/services/config-powersync/powersync.yaml @@ -25,6 +25,9 @@ telemetry: disable_telemetry_sharing: false + # Expose prometheus metrics on this port + prometheus_port: 9090 + # Settings for source database replication replication: # Specify database connection details diff --git a/services/powersync.yaml b/services/powersync.yaml index 63a74cb52..b279e5244 100644 --- a/services/powersync.yaml +++ b/services/powersync.yaml @@ -58,3 +58,7 @@ services: ports: - "8080:8080" + + # Expose prometheus metrics + expose: + - 9090 From 55e3378a919b845ff511034af9c1723d7cd2b474 Mon Sep 17 00:00:00 2001 From: Roland Geider Date: Wed, 22 Apr 2026 12:36:24 +0200 Subject: [PATCH 38/53] Cleanup --- config/prod.env | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/config/prod.env b/config/prod.env index 1d78560f4..84ae6716c 100644 --- a/config/prod.env +++ b/config/prod.env @@ -33,10 +33,15 @@ TZ=Europe/Berlin # # Other powersync settings +# postgres://:@:/ +# +PS_PG_URI=postgres://wger:wger@db:5432/wger +PS_STORAGE_PG_URI=postgres://powersync_storage:powersync_password@db:5432/wger +PS_PORT=8080 POWERSYNC_URL_PATH='ps' -# The full url for the powersync service, overrides POWERSYNC_URL_PATH. Only set if you -# know what you are doing and have a very different setup -#POWERSYNC_URL=http://ps.localhost +# The full url for the powersync service, overrides POWERSYNC_URL_PATH if set. Only +# set if you know what you are doing and have a very different setup +#POWERSYNC_URL=https://ps.my-domain.example.com:1234 # # If you get CSRF errors set your domain here @@ -127,14 +132,6 @@ DJANGO_DB_HOST=db DJANGO_DB_PORT=5432 DJANGO_PERFORM_MIGRATIONS=True # Perform any new database migrations on startup -# -# Powersync -# postgres://:@:/ -# Alternative: PS_STORAGE_MONGO_URI: mongodb://mongo:27017/powersync_wger -PS_PG_URI=postgres://wger:wger@db:5432/wger -PS_STORAGE_PG_URI=postgres://powersync_storage_user:secure_password@db:5432/wger -PS_PORT=8080 - # # Cache DJANGO_CACHE_BACKEND=django_redis.cache.RedisCache From 5771dab1757863865dd38eb774b6ce4feb52a787 Mon Sep 17 00:00:00 2001 From: Roland Geider Date: Tue, 28 Apr 2026 19:37:24 +0200 Subject: [PATCH 39/53] Update powersync storage user --- dev-postgres/initdb/04-powersync.sql | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/dev-postgres/initdb/04-powersync.sql b/dev-postgres/initdb/04-powersync.sql index 3818bd095..dbb6d0698 100644 --- a/dev-postgres/initdb/04-powersync.sql +++ b/dev-postgres/initdb/04-powersync.sql @@ -2,8 +2,8 @@ -- living inside the wger database (separate schema, no separate DB needed). -- https://docs.powersync.com/configuration/powersync-service/self-hosted-instances#postgres-storage -CREATE USER powersync_storage_user WITH PASSWORD 'secure_password'; -CREATE SCHEMA IF NOT EXISTS powersync AUTHORIZATION powersync_storage_user; -GRANT CONNECT ON DATABASE wger TO powersync_storage_user; -GRANT USAGE ON SCHEMA powersync TO powersync_storage_user; -GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA powersync TO powersync_storage_user; \ No newline at end of file +CREATE USER powersync_storage WITH PASSWORD 'powersync_password'; +CREATE SCHEMA IF NOT EXISTS powersync AUTHORIZATION powersync_storage; +GRANT CONNECT ON DATABASE wger TO powersync_storage; +GRANT USAGE ON SCHEMA powersync TO powersync_storage; +GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA powersync TO powersync_storage; \ No newline at end of file From f51b88dac78c2bc90f9495c74064ffdbe689bbea Mon Sep 17 00:00:00 2001 From: Roland Geider Date: Wed, 29 Apr 2026 10:12:58 +0200 Subject: [PATCH 40/53] Also sync the (base) routine and nutritional plan tables --- services/config-powersync/sync_rules.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/services/config-powersync/sync_rules.yaml b/services/config-powersync/sync_rules.yaml index 1f0e52c72..b965805ae 100644 --- a/services/config-powersync/sync_rules.yaml +++ b/services/config-powersync/sync_rules.yaml @@ -76,6 +76,7 @@ streams: - "SELECT uuid AS id, weight, date, user_id FROM weight_weightentry WHERE CAST(user_id AS TEXT) = auth.user_id()" # Routines + - "SELECT * FROM manager_routine WHERE CAST(user_id AS TEXT) = auth.user_id() AND is_template = FALSE" - "SELECT * FROM manager_workoutlog WHERE CAST(user_id AS TEXT) = auth.user_id()" - "SELECT * FROM manager_workoutsession WHERE CAST(user_id AS TEXT) = auth.user_id()" @@ -91,6 +92,7 @@ streams: # Nutrition # note: we are restricted by <=1000 distinct ingredient_id values here + - "SELECT * FROM nutrition_nutritionplan WHERE CAST(user_id AS TEXT) = auth.user_id()" - SELECT * FROM nutrition_ingredient WHERE id IN user_ingredients - | SELECT nutrition_image.* From 3b4f078c62d5860184693d7ecb6b79a394471849 Mon Sep 17 00:00:00 2001 From: Roland Geider Date: Wed, 29 Apr 2026 10:13:09 +0200 Subject: [PATCH 41/53] Cleanup, we don't use the mongo backend --- services/config-powersync/powersync.yaml | 2 -- 1 file changed, 2 deletions(-) diff --git a/services/config-powersync/powersync.yaml b/services/config-powersync/powersync.yaml index 6e9fb75be..4cce25765 100644 --- a/services/config-powersync/powersync.yaml +++ b/services/config-powersync/powersync.yaml @@ -54,8 +54,6 @@ storage: type: postgresql uri: !env PS_STORAGE_PG_URI sslmode: disable -# type: mongodb -# uri: !env PS_STORAGE_MONGO_URI # The port which the PowerSync API server will listen on port: !env PS_PORT From baaec88e0afaa4a1a4896f881b1bf2b1d00bd7a6 Mon Sep 17 00:00:00 2001 From: Roland Geider Date: Thu, 30 Apr 2026 14:37:12 +0200 Subject: [PATCH 42/53] Sync the ingredient units as well --- services/config-powersync/sync_rules.yaml | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/services/config-powersync/sync_rules.yaml b/services/config-powersync/sync_rules.yaml index b965805ae..fc0008710 100644 --- a/services/config-powersync/sync_rules.yaml +++ b/services/config-powersync/sync_rules.yaml @@ -98,7 +98,9 @@ streams: SELECT nutrition_image.* FROM nutrition_image - JOIN - nutrition_ingredient ON nutrition_ingredient.id = nutrition_image.ingredient_id - WHERE nutrition_ingredient.id IN user_ingredients - + WHERE nutrition_image.ingredient_id IN user_ingredients + - | + SELECT nutrition_ingredientweightunit.* + FROM + nutrition_ingredientweightunit + WHERE nutrition_ingredientweightunit.ingredient_id IN user_ingredients From 28a5c2e7e98ab9f0b282280fa906c9bae0d52d0d Mon Sep 17 00:00:00 2001 From: Roland Geider Date: Fri, 1 May 2026 14:09:43 +0200 Subject: [PATCH 43/53] Sync nutrition logs as well --- services/config-powersync/sync_rules.yaml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/services/config-powersync/sync_rules.yaml b/services/config-powersync/sync_rules.yaml index fc0008710..4205bf631 100644 --- a/services/config-powersync/sync_rules.yaml +++ b/services/config-powersync/sync_rules.yaml @@ -104,3 +104,17 @@ streams: FROM nutrition_ingredientweightunit WHERE nutrition_ingredientweightunit.ingredient_id IN user_ingredients + - | + SELECT + nutrition_logitem.uuid AS id, + nutrition_logitem.plan_id, + nutrition_logitem.meal_id, + nutrition_logitem.ingredient_id, + nutrition_logitem.weight_unit_id, + nutrition_logitem.datetime, + nutrition_logitem.amount, + nutrition_logitem.comment + FROM nutrition_logitem + JOIN nutrition_nutritionplan + ON nutrition_logitem.plan_id = nutrition_nutritionplan.id + WHERE CAST(nutrition_nutritionplan.user_id AS TEXT) = auth.user_id() From 4d0cb20526d22da0f7748312adb70c6ede5b9f3f Mon Sep 17 00:00:00 2001 From: Roland Geider Date: Fri, 1 May 2026 14:41:22 +0200 Subject: [PATCH 44/53] Sync gallery entries to powersync --- services/config-powersync/sync_rules.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/services/config-powersync/sync_rules.yaml b/services/config-powersync/sync_rules.yaml index 4205bf631..86dd9c480 100644 --- a/services/config-powersync/sync_rules.yaml +++ b/services/config-powersync/sync_rules.yaml @@ -118,3 +118,6 @@ streams: JOIN nutrition_nutritionplan ON nutrition_logitem.plan_id = nutrition_nutritionplan.id WHERE CAST(nutrition_nutritionplan.user_id AS TEXT) = auth.user_id() + + # Gallery + - "SELECT * FROM gallery_image WHERE CAST(user_id AS TEXT) = auth.user_id()" From 4fed52f9271838f6dad8efec972df63e97233625 Mon Sep 17 00:00:00 2001 From: Roland Geider Date: Fri, 1 May 2026 20:22:50 +0200 Subject: [PATCH 45/53] Sync the rest of the nutrition tables to powersync --- services/config-powersync/sync_rules.yaml | 52 ++++++++++++++++++++--- 1 file changed, 47 insertions(+), 5 deletions(-) diff --git a/services/config-powersync/sync_rules.yaml b/services/config-powersync/sync_rules.yaml index 86dd9c480..684f4dc1d 100644 --- a/services/config-powersync/sync_rules.yaml +++ b/services/config-powersync/sync_rules.yaml @@ -90,9 +90,49 @@ streams: ON measurements_measurement.category_id = measurements_category.id WHERE CAST(measurements_category.user_id AS TEXT) = auth.user_id() - # Nutrition - # note: we are restricted by <=1000 distinct ingredient_id values here - - "SELECT * FROM nutrition_nutritionplan WHERE CAST(user_id AS TEXT) = auth.user_id()" + # Nutrition (note: we are restricted by <=1000 distinct ingredient_id values here) + - | + SELECT + nutrition_nutritionplan.uuid AS id, + nutrition_nutritionplan.user_id, + nutrition_nutritionplan.creation_date, + nutrition_nutritionplan.start, + nutrition_nutritionplan.end, + nutrition_nutritionplan.description, + nutrition_nutritionplan.only_logging, + nutrition_nutritionplan.goal_energy, + nutrition_nutritionplan.goal_protein, + nutrition_nutritionplan.goal_carbohydrates, + nutrition_nutritionplan.goal_fiber, + nutrition_nutritionplan.goal_fat, + nutrition_nutritionplan.has_goal_calories + FROM nutrition_nutritionplan + WHERE CAST(nutrition_nutritionplan.user_id AS TEXT) = auth.user_id() + - | + SELECT + nutrition_meal.uuid AS id, + nutrition_nutritionplan.uuid AS plan_id, + nutrition_meal.order, + nutrition_meal.time, + nutrition_meal.name + FROM nutrition_meal + JOIN nutrition_nutritionplan + ON nutrition_meal.plan_id = nutrition_nutritionplan.id + WHERE CAST(nutrition_nutritionplan.user_id AS TEXT) = auth.user_id() + - | + SELECT + nutrition_mealitem.uuid AS id, + nutrition_meal.uuid AS meal_id, + nutrition_mealitem.ingredient_id, + nutrition_mealitem.weight_unit_id, + nutrition_mealitem.order, + nutrition_mealitem.amount + 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 CAST(nutrition_nutritionplan.user_id AS TEXT) = auth.user_id() - SELECT * FROM nutrition_ingredient WHERE id IN user_ingredients - | SELECT nutrition_image.* @@ -107,8 +147,8 @@ streams: - | SELECT nutrition_logitem.uuid AS id, - nutrition_logitem.plan_id, - nutrition_logitem.meal_id, + nutrition_nutritionplan.uuid AS plan_id, + nutrition_meal.uuid AS meal_id, nutrition_logitem.ingredient_id, nutrition_logitem.weight_unit_id, nutrition_logitem.datetime, @@ -117,6 +157,8 @@ streams: FROM nutrition_logitem JOIN nutrition_nutritionplan ON nutrition_logitem.plan_id = nutrition_nutritionplan.id + LEFT JOIN nutrition_meal + ON nutrition_logitem.meal_id = nutrition_meal.id WHERE CAST(nutrition_nutritionplan.user_id AS TEXT) = auth.user_id() # Gallery From a8e84a7ce7278c221825670bf0caf6a5589b8f6a Mon Sep 17 00:00:00 2001 From: Roland Geider Date: Sat, 2 May 2026 16:18:15 +0200 Subject: [PATCH 46/53] Simplify sync rules --- services/config-powersync/sync_rules.yaml | 62 +++++------------------ 1 file changed, 12 insertions(+), 50 deletions(-) diff --git a/services/config-powersync/sync_rules.yaml b/services/config-powersync/sync_rules.yaml index 684f4dc1d..515f62f5e 100644 --- a/services/config-powersync/sync_rules.yaml +++ b/services/config-powersync/sync_rules.yaml @@ -73,60 +73,32 @@ streams: ) queries: # Weight - - "SELECT uuid AS id, weight, date, user_id FROM weight_weightentry WHERE CAST(user_id AS TEXT) = auth.user_id()" + - SELECT uuid AS id, weight, date, user_id FROM weight_weightentry WHERE CAST(user_id AS TEXT) = auth.user_id() # Routines - - "SELECT * FROM manager_routine WHERE CAST(user_id AS TEXT) = auth.user_id() AND is_template = FALSE" - - "SELECT * FROM manager_workoutlog WHERE CAST(user_id AS TEXT) = auth.user_id()" - - "SELECT * FROM manager_workoutsession WHERE CAST(user_id AS TEXT) = auth.user_id()" + - SELECT * FROM manager_routine WHERE CAST(user_id AS TEXT) = auth.user_id() AND is_template = FALSE + - SELECT * FROM manager_workoutlog WHERE CAST(user_id AS TEXT) = auth.user_id() + - SELECT * FROM manager_workoutsession WHERE CAST(user_id AS TEXT) = auth.user_id() # Measurements - - "SELECT * FROM measurements_category WHERE CAST(user_id AS TEXT) = auth.user_id()" + - SELECT * FROM measurements_category WHERE CAST(user_id AS TEXT) = auth.user_id() - | - SELECT - measurements_measurement.* + SELECT measurements_measurement.* FROM measurements_measurement INNER JOIN measurements_category ON measurements_measurement.category_id = measurements_category.id - WHERE CAST(measurements_category.user_id AS TEXT) = auth.user_id() + WHERE CAST(measurements_category.user_id AS TEXT) = auth.user_id() # Nutrition (note: we are restricted by <=1000 distinct ingredient_id values here) + - SELECT * FROM nutrition_nutritionplan WHERE CAST(user_id AS TEXT) = auth.user_id() - | - SELECT - nutrition_nutritionplan.uuid AS id, - nutrition_nutritionplan.user_id, - nutrition_nutritionplan.creation_date, - nutrition_nutritionplan.start, - nutrition_nutritionplan.end, - nutrition_nutritionplan.description, - nutrition_nutritionplan.only_logging, - nutrition_nutritionplan.goal_energy, - nutrition_nutritionplan.goal_protein, - nutrition_nutritionplan.goal_carbohydrates, - nutrition_nutritionplan.goal_fiber, - nutrition_nutritionplan.goal_fat, - nutrition_nutritionplan.has_goal_calories - FROM nutrition_nutritionplan - WHERE CAST(nutrition_nutritionplan.user_id AS TEXT) = auth.user_id() - - | - SELECT - nutrition_meal.uuid AS id, - nutrition_nutritionplan.uuid AS plan_id, - nutrition_meal.order, - nutrition_meal.time, - nutrition_meal.name + SELECT nutrition_meal.* FROM nutrition_meal JOIN nutrition_nutritionplan ON nutrition_meal.plan_id = nutrition_nutritionplan.id WHERE CAST(nutrition_nutritionplan.user_id AS TEXT) = auth.user_id() - | - SELECT - nutrition_mealitem.uuid AS id, - nutrition_meal.uuid AS meal_id, - nutrition_mealitem.ingredient_id, - nutrition_mealitem.weight_unit_id, - nutrition_mealitem.order, - nutrition_mealitem.amount + SELECT nutrition_mealitem.* FROM nutrition_mealitem JOIN nutrition_meal ON nutrition_mealitem.meal_id = nutrition_meal.id @@ -145,21 +117,11 @@ streams: nutrition_ingredientweightunit WHERE nutrition_ingredientweightunit.ingredient_id IN user_ingredients - | - SELECT - nutrition_logitem.uuid AS id, - nutrition_nutritionplan.uuid AS plan_id, - nutrition_meal.uuid AS meal_id, - nutrition_logitem.ingredient_id, - nutrition_logitem.weight_unit_id, - nutrition_logitem.datetime, - nutrition_logitem.amount, - nutrition_logitem.comment + SELECT nutrition_logitem.* FROM nutrition_logitem JOIN nutrition_nutritionplan ON nutrition_logitem.plan_id = nutrition_nutritionplan.id - LEFT JOIN nutrition_meal - ON nutrition_logitem.meal_id = nutrition_meal.id WHERE CAST(nutrition_nutritionplan.user_id AS TEXT) = auth.user_id() # Gallery - - "SELECT * FROM gallery_image WHERE CAST(user_id AS TEXT) = auth.user_id()" + - SELECT * FROM gallery_image WHERE CAST(user_id AS TEXT) = auth.user_id() From 669fdc2b336821d7f30a91f137bc3f65b7e68b19 Mon Sep 17 00:00:00 2001 From: Roland Geider Date: Sat, 16 May 2026 16:24:21 +0200 Subject: [PATCH 47/53] Update tests --- .github/workflows/test-nginx.yml | 3 +- tests/docker-compose.test.yml | 20 +++++++++- tests/test_nginx_config.py | 65 ++++++++++++++++++++++++++++++++ 3 files changed, 85 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test-nginx.yml b/.github/workflows/test-nginx.yml index c77b0a53c..90894a08e 100644 --- a/.github/workflows/test-nginx.yml +++ b/.github/workflows/test-nginx.yml @@ -27,6 +27,7 @@ jobs: run: | docker run --rm \ --add-host=web:127.0.0.1 \ + --add-host=powersync:127.0.0.1 \ --volume ${{ github.workspace }}/config/nginx.conf:/etc/nginx/conf.d/default.conf:ro \ nginx:alpine nginx -t @@ -45,7 +46,7 @@ jobs: - name: Start test services run: | cd tests - docker compose -f docker-compose.test.yml up -d web nginx + docker compose -f docker-compose.test.yml up -d web powersync nginx # Wait for services to be healthy echo "Waiting for services to be ready..." diff --git a/tests/docker-compose.test.yml b/tests/docker-compose.test.yml index e7417beb7..6e59d566b 100644 --- a/tests/docker-compose.test.yml +++ b/tests/docker-compose.test.yml @@ -21,12 +21,26 @@ services: timeout: 3s retries: 3 + # Mock PowerSync service (same echo backend on the port nginx expects) + powersync: + image: python:3.11-slim + container_name: test_powersync + working_dir: /app + volumes: + - ./mock_backend.py:/app/mock_backend.py:ro + command: python3 mock_backend.py 8080 + networks: + - test_network + healthcheck: + test: ["CMD", "python3", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:8080')"] + interval: 5s + timeout: 3s + retries: 3 + # nginx with our configuration nginx: image: nginx:alpine container_name: test_nginx - ports: - - "8080:80" volumes: - ../config/nginx.conf:/etc/nginx/conf.d/default.conf:ro networks: @@ -34,6 +48,8 @@ services: depends_on: web: condition: service_healthy + powersync: + condition: service_healthy healthcheck: test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://127.0.0.1:80/"] interval: 5s diff --git a/tests/test_nginx_config.py b/tests/test_nginx_config.py index cffc7dc3d..cd35c348f 100644 --- a/tests/test_nginx_config.py +++ b/tests/test_nginx_config.py @@ -132,3 +132,68 @@ def test_host_header_forwarding(self, nginx_url): "Host header not forwarded to backend" assert data['headers']['Host'] == 'example.com', \ f"Expected Host: example.com, got {data['headers']['Host']}" + + +class TestPowerSyncProxy: + """Test the /ps/ reverse proxy to the PowerSync service""" + + def test_strips_ps_prefix_from_path(self, nginx_url): + """Verify /ps/ is forwarded to the upstream as /""" + response = requests.get(f"{nginx_url}/ps/sync/stream") + + assert response.status_code == 200, f"Expected 200 OK, got {response.status_code}" + data = response.json() + + assert data['path'] == '/sync/stream', \ + f"Expected upstream path '/sync/stream', got {data['path']}" + + def test_strips_ps_prefix_for_root(self, nginx_url): + """Verify /ps/ (no further path) is forwarded as /""" + response = requests.get(f"{nginx_url}/ps/") + + assert response.status_code == 200, f"Expected 200 OK, got {response.status_code}" + data = response.json() + + assert data['path'] == '/', \ + f"Expected upstream path '/', got {data['path']}" + + def test_proxies_websocket_upgrade_headers(self, nginx_url): + """Verify /ps/ proxies WebSocket Upgrade/Connection headers (Web SDK + diagnostics)""" + response = requests.get( + f"{nginx_url}/ps/sync/stream", + headers={ + 'Upgrade': 'websocket', + 'Connection': 'upgrade', + }, + ) + + assert response.status_code == 200, f"Expected 200 OK, got {response.status_code}" + data = response.json() + + assert data['headers'].get('Upgrade') == 'websocket', \ + f"Expected Upgrade: websocket, got {data['headers'].get('Upgrade')}" + assert data['headers'].get('Connection') == 'upgrade', \ + f"Expected Connection: upgrade, got {data['headers'].get('Connection')}" + + def test_preserves_x_forwarded_proto_from_upstream(self, nginx_url): + """Verify /ps/ respects X-Forwarded-Proto from an upstream reverse proxy""" + response = requests.get( + f"{nginx_url}/ps/sync/stream", + headers={'X-Forwarded-Proto': 'https'}, + ) + + assert response.status_code == 200, f"Expected 200 OK, got {response.status_code}" + data = response.json() + + assert data['headers'].get('X-Forwarded-Proto') == 'https', \ + f"Expected X-Forwarded-Proto: https, got {data['headers'].get('X-Forwarded-Proto')}" + + def test_falls_back_to_scheme_without_upstream_proto(self, nginx_url): + """Verify /ps/ falls back to $scheme (http) when no upstream X-Forwarded-Proto is set""" + response = requests.get(f"{nginx_url}/ps/sync/stream") + + assert response.status_code == 200, f"Expected 200 OK, got {response.status_code}" + data = response.json() + + assert data['headers'].get('X-Forwarded-Proto') == 'http', \ + f"Expected fallback to $scheme (http), got {data['headers'].get('X-Forwarded-Proto')}" From 48af9507f5ce9659781cde6f45edfad7bb139a3c Mon Sep 17 00:00:00 2001 From: Roland Geider Date: Sat, 16 May 2026 21:35:54 +0200 Subject: [PATCH 48/53] Consolidate JWT Keys --- config/prod.env | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/config/prod.env b/config/prod.env index 84ae6716c..91c5a16bd 100644 --- a/config/prod.env +++ b/config/prod.env @@ -5,21 +5,18 @@ # Django's secret keys, change to a 50 character random string. Generate e.g. with: # * python -c "import secrets; print(secrets.token_urlsafe(50))" or # * https://djecrety.ir/ -# Note that if you leave these keys unchanged, new ones will be generated on every +# Note that if you leave this key unchanged, a new one will be generated on every # startup, which means that for example all sessions will be invalidated every time # you restart the server. SECRET_KEY=wger-docker-supersecret-key-1234567890!@#$%^&*(-_) -# Signing key used for JWT, use something different than the secret key -SIGNING_KEY=wger-docker-secret-jwtkey-1234567890!@#$%^&*(-_=+) - # The URL where the application will be available. SITE_URL=http://localhost -# Powersync JWT keys, used by the mobile app. This default NEEDS to be changed. -# New keys can be generated with: docker compose exec web ./manage.py generate-powersync-keys -POWERSYNC_JWKS_PUBLIC_KEY=eyJhbGciOiAiUlMyNTYiLCAia3R5IjogIlJTQSIsICJuIjogInFhdVVnb0ZXenRNcjVEYks3bFIxZXUxazJrdllyblJkRGh1NDFyWnFLeWhDWkJya0FTS0d0N25KbVUwVEpKb1d0cFF2eHVvc0ZGeW1BMUhXQnNaY0dtVlcxdlowdDJlazl4THg5bjg2UWRIVWc1MktsRG9ZUzNtRTFaWW5BYzJfRDM3UmxyQkVxRXpuSnBNeDJ3VkpLcVdRZHlWSWh6Q082YzRnOWN3VExGbUhkVXVURXMzdDNBN1MyNENrUkM2TE1KSFFvRTJzay1uWlJyZE9fTHVNNUJJcVp2b1dWUC1Salp4OWk4OGdaaDhvOEcyWW1xZnMwczRzYW1fam85bmFaYlo4aFBFQ0FZdnZUZ29ObzRHMGpXZERZeGdPWHlXTE80bTk1SEdMSFJMZjZ5M29vdkZad2QwN2FFbThEU3dBX3hsY1V4WHNNZ0ZlYVVVZkp2NEV4USIsICJlIjogIkFRQUIiLCAia2lkIjogInBvd2Vyc3luYyJ9 -POWERSYNC_JWKS_PRIVATE_KEY=eyJhbGciOiAiUlMyNTYiLCAia3R5IjogIlJTQSIsICJuIjogInFhdVVnb0ZXenRNcjVEYks3bFIxZXUxazJrdllyblJkRGh1NDFyWnFLeWhDWkJya0FTS0d0N25KbVUwVEpKb1d0cFF2eHVvc0ZGeW1BMUhXQnNaY0dtVlcxdlowdDJlazl4THg5bjg2UWRIVWc1MktsRG9ZUzNtRTFaWW5BYzJfRDM3UmxyQkVxRXpuSnBNeDJ3VkpLcVdRZHlWSWh6Q082YzRnOWN3VExGbUhkVXVURXMzdDNBN1MyNENrUkM2TE1KSFFvRTJzay1uWlJyZE9fTHVNNUJJcVp2b1dWUC1Salp4OWk4OGdaaDhvOEcyWW1xZnMwczRzYW1fam85bmFaYlo4aFBFQ0FZdnZUZ29ObzRHMGpXZERZeGdPWHlXTE80bTk1SEdMSFJMZjZ5M29vdkZad2QwN2FFbThEU3dBX3hsY1V4WHNNZ0ZlYVVVZkp2NEV4USIsICJlIjogIkFRQUIiLCAiZCI6ICJQZXVwNjhUakZ1RVhaQmFoRWNDT0RWcEUwNndaZkhWb0hvVjhmQk9maEhlUlh6STNJcmprZkhtWHV0UlhsNlNLaElCcFBVbHA0OVo2R2IwTWhIVncySXRDV1hvaFYydkNWdzg1Y2RHMXc1NmQxWml4b2UzZnZ1LXV6RG9icXp0WXJvR0VZTi1jZHVWMS1HeUFwZU4wYzlWdmR5UUtwNWZQbUVGTFl4amlxR3k5UUhyTldpcGJmZXdPUGY0YUl4X05VRnE3R1BsUk1yalA4VEhvSzNPOVNfXzJpR09LRVpINDFUWkpscVBZX0s5dFNkbFNKd1FPWEtwOFc2ZUdGT3l2MElueVhsUXhHb0ZBWVNrUC12WTlWQy1vTUtzdmhocm1GeGM0VlU2OUZ3VWFJYUdaOU9jaXF4M3B0aE9sU1drRjFhbEtxNWFJZ2VHbEUzM2VyNGthSXciLCAicCI6ICI1WDN0QzN4Z0hwbm91U1JwSlg4c0ZWRm5vamhxMWJoWkF3c3VRaXBxWWgtZmJNRGI4a2NTTy1fT3BEMExNekYzcHp0dVNRb0NZOFc0WjI0TEJ6cFRuUlFid0JrYWt3VDMybmZIU1J0d3RnM1ZjWkkxZFNsdHgtclhEcHlBMDNHa1RvLUxEZkp1UzF0a1FYQXB0OTBkcnJHMndjQ25oRXc4bGx2SzR2cWRucHMiLCAicSI6ICJ2VVM2V2QtY2trTUJMVmJvSkVaVnRtMlFLTFE2dV9oZEFrbTFWa3dGajMxZWZWRTlFRWRSa0F0dGVoOWh2ZzBkM2FXVDZ1bFQ4YlpubWo3WkFjNG55aVdwOTlFd0k5U0hFX01UUE11YVZSeUw5SmFIX2R0Uk5nVGE5UV9hZUs2d1pkY3RwLUZRT1lteVlDWmhzRnVOTG45TFJ3UklJOVJ0YlBXYW55X01jQjgiLCAiZHAiOiAiWjFNNkhmakN3aVJqcnJBaEV6dmQyajlMbkxNd0RzZXdjX2xkdTNhamJVaDFuQjU5S09rczRZV0lFVlJXclpieEczOWJtVkVEWUc2T0p5dFpsY2lDQ3ZBWnluVEREVHlvWjFtVWhXcndaVmQzS1dvOTNXRm94eUVKOE04d0JZTmVDZTBCRzZkeVYwVnZyekxUNWEtTmhMRUk2dFZWMXZBSU8xNWF5N1V3c0U4IiwgImRxIjogIktsclpBUWZEZUEtNmtiVGpHa3NMSDFvQmFycDZjbG93SmpUc2ViVmxnU2pqSGxReHdCVFZzZEI4M1Zsc2ZDVmZTNXlrTDJ1cnQybkVZWVl5OWU1MmhReE1yd0tITFYyQUpQeS1qMXBZM1RjWU10SUUtTkE5cWtNSDVOTjVab3hoT1VrZ0ZIT2RpbUxBSWpnMG9FeThtVzB2SVdOWjZYcS1TaVhrUmo5aUZxMCIsICJxaSI6ICJzSV84RTh0MTBsRDY2NTh3UXRpY19BaUUxOVk1Rms0SDJWbnpGclBhVU04aWFNaVc2eUZxMFZuN3RXa2RTWS1STTB1SFMwdmVmSEcyZTBKSWxEanhBUmZWZUcwNTFyVUNRZjBkSnR4U0ZDQUp2eGxMRTZsYjZOQlUwZVIyMld6bjVob1ZZTVpHZnQ5QnA0SlVOOHJkMF9lMm1kSjhxc09wM1NLQ3NTSTByUkkiLCAia2lkIjogInBvd2Vyc3luYyJ9 +# JWT keys, used by the mobile app. This default NEEDS to be changed. +# Generate fresh keys with: docker compose exec web ./manage.py generate-jwt-keys +JWT_PUBLIC_KEY=eyJhbGciOiAiUlMyNTYiLCAia3R5IjogIlJTQSIsICJuIjogInFhdVVnb0ZXenRNcjVEYks3bFIxZXUxazJrdllyblJkRGh1NDFyWnFLeWhDWkJya0FTS0d0N25KbVUwVEpKb1d0cFF2eHVvc0ZGeW1BMUhXQnNaY0dtVlcxdlowdDJlazl4THg5bjg2UWRIVWc1MktsRG9ZUzNtRTFaWW5BYzJfRDM3UmxyQkVxRXpuSnBNeDJ3VkpLcVdRZHlWSWh6Q082YzRnOWN3VExGbUhkVXVURXMzdDNBN1MyNENrUkM2TE1KSFFvRTJzay1uWlJyZE9fTHVNNUJJcVp2b1dWUC1Salp4OWk4OGdaaDhvOEcyWW1xZnMwczRzYW1fam85bmFaYlo4aFBFQ0FZdnZUZ29ObzRHMGpXZERZeGdPWHlXTE80bTk1SEdMSFJMZjZ5M29vdkZad2QwN2FFbThEU3dBX3hsY1V4WHNNZ0ZlYVVVZkp2NEV4USIsICJlIjogIkFRQUIiLCAia2lkIjogInBvd2Vyc3luYyJ9 +JWT_PRIVATE_KEY=eyJhbGciOiAiUlMyNTYiLCAia3R5IjogIlJTQSIsICJuIjogInFhdVVnb0ZXenRNcjVEYks3bFIxZXUxazJrdllyblJkRGh1NDFyWnFLeWhDWkJya0FTS0d0N25KbVUwVEpKb1d0cFF2eHVvc0ZGeW1BMUhXQnNaY0dtVlcxdlowdDJlazl4THg5bjg2UWRIVWc1MktsRG9ZUzNtRTFaWW5BYzJfRDM3UmxyQkVxRXpuSnBNeDJ3VkpLcVdRZHlWSWh6Q082YzRnOWN3VExGbUhkVXVURXMzdDNBN1MyNENrUkM2TE1KSFFvRTJzay1uWlJyZE9fTHVNNUJJcVp2b1dWUC1Salp4OWk4OGdaaDhvOEcyWW1xZnMwczRzYW1fam85bmFaYlo4aFBFQ0FZdnZUZ29ObzRHMGpXZERZeGdPWHlXTE80bTk1SEdMSFJMZjZ5M29vdkZad2QwN2FFbThEU3dBX3hsY1V4WHNNZ0ZlYVVVZkp2NEV4USIsICJlIjogIkFRQUIiLCAiZCI6ICJQZXVwNjhUakZ1RVhaQmFoRWNDT0RWcEUwNndaZkhWb0hvVjhmQk9maEhlUlh6STNJcmprZkhtWHV0UlhsNlNLaElCcFBVbHA0OVo2R2IwTWhIVncySXRDV1hvaFYydkNWdzg1Y2RHMXc1NmQxWml4b2UzZnZ1LXV6RG9icXp0WXJvR0VZTi1jZHVWMS1HeUFwZU4wYzlWdmR5UUtwNWZQbUVGTFl4amlxR3k5UUhyTldpcGJmZXdPUGY0YUl4X05VRnE3R1BsUk1yalA4VEhvSzNPOVNfXzJpR09LRVpINDFUWkpscVBZX0s5dFNkbFNKd1FPWEtwOFc2ZUdGT3l2MElueVhsUXhHb0ZBWVNrUC12WTlWQy1vTUtzdmhocm1GeGM0VlU2OUZ3VWFJYUdaOU9jaXF4M3B0aE9sU1drRjFhbEtxNWFJZ2VHbEUzM2VyNGthSXciLCAicCI6ICI1WDN0QzN4Z0hwbm91U1JwSlg4c0ZWRm5vamhxMWJoWkF3c3VRaXBxWWgtZmJNRGI4a2NTTy1fT3BEMExNekYzcHp0dVNRb0NZOFc0WjI0TEJ6cFRuUlFid0JrYWt3VDMybmZIU1J0d3RnM1ZjWkkxZFNsdHgtclhEcHlBMDNHa1RvLUxEZkp1UzF0a1FYQXB0OTBkcnJHMndjQ25oRXc4bGx2SzR2cWRucHMiLCAicSI6ICJ2VVM2V2QtY2trTUJMVmJvSkVaVnRtMlFLTFE2dV9oZEFrbTFWa3dGajMxZWZWRTlFRWRSa0F0dGVoOWh2ZzBkM2FXVDZ1bFQ4YlpubWo3WkFjNG55aVdwOTlFd0k5U0hFX01UUE11YVZSeUw5SmFIX2R0Uk5nVGE5UV9hZUs2d1pkY3RwLUZRT1lteVlDWmhzRnVOTG45TFJ3UklJOVJ0YlBXYW55X01jQjgiLCAiZHAiOiAiWjFNNkhmakN3aVJqcnJBaEV6dmQyajlMbkxNd0RzZXdjX2xkdTNhamJVaDFuQjU5S09rczRZV0lFVlJXclpieEczOWJtVkVEWUc2T0p5dFpsY2lDQ3ZBWnluVEREVHlvWjFtVWhXcndaVmQzS1dvOTNXRm94eUVKOE04d0JZTmVDZTBCRzZkeVYwVnZyekxUNWEtTmhMRUk2dFZWMXZBSU8xNWF5N1V3c0U4IiwgImRxIjogIktsclpBUWZEZUEtNmtiVGpHa3NMSDFvQmFycDZjbG93SmpUc2ViVmxnU2pqSGxReHdCVFZzZEI4M1Zsc2ZDVmZTNXlrTDJ1cnQybkVZWVl5OWU1MmhReE1yd0tITFYyQUpQeS1qMXBZM1RjWU10SUUtTkE5cWtNSDVOTjVab3hoT1VrZ0ZIT2RpbUxBSWpnMG9FeThtVzB2SVdOWjZYcS1TaVhrUmo5aUZxMCIsICJxaSI6ICJzSV84RTh0MTBsRDY2NTh3UXRpY19BaUUxOVk1Rms0SDJWbnpGclBhVU04aWFNaVc2eUZxMFZuN3RXa2RTWS1STTB1SFMwdmVmSEcyZTBKSWxEanhBUmZWZUcwNTFyVUNRZjBkSnR4U0ZDQUp2eGxMRTZsYjZOQlUwZVIyMld6bjVob1ZZTVpHZnQ5QnA0SlVOOHJkMF9lMm1kSjhxc09wM1NLQ3NTSTByUkkiLCAia2lkIjogInBvd2Vyc3luYyJ9 # The server's timezone, for a list of possible names: # https://en.wikipedia.org/wiki/List_of_tz_database_time_zones From 429d7349a56d0150b8ad0fc29e65dc2ed80c4891 Mon Sep 17 00:00:00 2001 From: Roland Geider Date: Mon, 18 May 2026 15:09:09 +0200 Subject: [PATCH 49/53] Consolidate the db configuration into PS_DATABASE_URI --- config/prod.env | 18 ++++++++---------- services/config-powersync/powersync.yaml | 2 +- services/postgres.yaml | 7 +++---- 3 files changed, 12 insertions(+), 15 deletions(-) diff --git a/config/prod.env b/config/prod.env index 6c799b711..bb4970e76 100644 --- a/config/prod.env +++ b/config/prod.env @@ -27,12 +27,8 @@ TZ=Europe/Berlin # These settings usually don't need changing # - # # Other powersync settings -# postgres://:@:/ -# -PS_PG_URI=postgres://wger:wger@db:5432/wger PS_STORAGE_PG_URI=postgres://powersync_storage:powersync_password@db:5432/wger PS_PORT=8080 POWERSYNC_URL_PATH='ps' @@ -121,12 +117,14 @@ CELERY_WORKER_CONCURRENCY=4 # Set to one if using sqlite # # Database -DJANGO_DB_ENGINE=django.db.backends.postgresql -DJANGO_DB_DATABASE=wger -DJANGO_DB_USER=wger -DJANGO_DB_PASSWORD=wger -DJANGO_DB_HOST=db -DJANGO_DB_PORT=5432 +# +# The Postgres container reads POSTGRES_USER / POSTGRES_PASSWORD / POSTGRES_DB +# directly from this file. If you change the password, also update it inside PS_DATABASE_URI. +POSTGRES_USER=wger +POSTGRES_PASSWORD=wger +POSTGRES_DB=wger +PS_DATABASE_URI=postgres://wger:wger@db:5432/wger + DJANGO_PERFORM_MIGRATIONS=True # Perform any new database migrations on startup # diff --git a/services/config-powersync/powersync.yaml b/services/config-powersync/powersync.yaml index 4cce25765..bf504c7e4 100644 --- a/services/config-powersync/powersync.yaml +++ b/services/config-powersync/powersync.yaml @@ -35,7 +35,7 @@ replication: # Multiple connection support is on the roadmap connections: - type: postgresql - uri: !env PS_PG_URI + uri: !env PS_DATABASE_URI # Or use individual params # hostname: db # From the Docker Compose service name diff --git a/services/postgres.yaml b/services/postgres.yaml index 2528122e9..714fb473f 100644 --- a/services/postgres.yaml +++ b/services/postgres.yaml @@ -1,10 +1,9 @@ services: db: image: docker.io/postgres:15-alpine + env_file: + - ../config/prod.env environment: - - POSTGRES_USER=wger - - POSTGRES_PASSWORD=wger - - POSTGRES_DB=wger - TZ=Europe/Berlin logging: driver: json-file @@ -18,7 +17,7 @@ services: # "-c", "log_statement=all", "-c", "log_min_error_statement=DEBUG1" command: [ "postgres", "-c", "wal_level=logical" ] healthcheck: - test: pg_isready -U wger + test: ["CMD-SHELL", "pg_isready -U \"$$POSTGRES_USER\""] interval: 10s timeout: 5s retries: 5 From b1cf3561f779b234f590bebb0a58494ae134bd97 Mon Sep 17 00:00:00 2001 From: Roland Geider Date: Wed, 20 May 2026 16:14:21 +0200 Subject: [PATCH 50/53] Add consistent logging options for the services --- docker-compose.override.example.yml | 15 ++++++++++++++ docker-compose.yml | 31 +++++++++++++++++------------ grafana/docker-compose.yml | 25 +++++++++++++++++++++++ services/postgres.yaml | 10 +++++----- services/powersync.yaml | 5 +++++ services/redis.yaml | 8 ++++---- 6 files changed, 72 insertions(+), 22 deletions(-) diff --git a/docker-compose.override.example.yml b/docker-compose.override.example.yml index f88a52d96..f8e15b86e 100644 --- a/docker-compose.override.example.yml +++ b/docker-compose.override.example.yml @@ -26,6 +26,11 @@ services: # Generate the ED25519 private key with "openssl rand -hex 32" anubis: image: ghcr.io/techarohq/anubis:latest + logging: + driver: json-file + options: + max-size: 10m + max-file: 3 pull_policy: always environment: BIND: ":3000" @@ -55,6 +60,11 @@ services: # caddy: # image: docker.io/caddy:latest +# logging: +# driver: json-file +# options: +# max-size: 10m +# max-file: 3 # depends_on: # - web # ports: @@ -75,6 +85,11 @@ services: celery_flower: image: docker.io/wger/server:latest + logging: + driver: json-file + options: + max-size: 10m + max-file: 3 command: /start-flower env_file: - ./config/prod.env diff --git a/docker-compose.yml b/docker-compose.yml index 52c00a0fa..81c258252 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -8,6 +8,11 @@ services: web: image: docker.io/wger/server:latest + logging: + driver: json-file + options: + max-size: 10m + max-file: 3 depends_on: db: condition: service_healthy @@ -20,11 +25,6 @@ services: - media:/home/wger/media expose: - 8000 - logging: - driver: json-file - options: - max-size: 5m - max-file: 5 healthcheck: test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:8000"] interval: 10s @@ -42,6 +42,11 @@ services: nginx: image: docker.io/nginx:stable + logging: + driver: json-file + options: + max-size: 10m + max-file: 3 depends_on: - web - powersync @@ -79,16 +84,16 @@ services: celery_worker: image: docker.io/wger/server:latest + logging: + driver: json-file + options: + max-size: 10m + max-file: 3 command: /start-worker env_file: - ./config/prod.env volumes: - media:/home/wger/media - logging: - driver: json-file - options: - max-size: 5m - max-file: 5 depends_on: web: condition: service_healthy @@ -102,12 +107,12 @@ services: celery_beat: image: docker.io/wger/server:latest - command: /start-beat logging: driver: json-file options: - max-size: 5m - max-file: 5 + max-size: 10m + max-file: 3 + command: /start-beat volumes: - celery-beat:/home/wger/beat/ env_file: diff --git a/grafana/docker-compose.yml b/grafana/docker-compose.yml index ca4487482..48ac179bf 100644 --- a/grafana/docker-compose.yml +++ b/grafana/docker-compose.yml @@ -1,6 +1,11 @@ services: prometheus: image: prom/prometheus:latest + logging: + driver: json-file + options: + max-size: 10m + max-file: 3 restart: unless-stopped volumes: - prometheus_data:/prometheus @@ -22,6 +27,11 @@ services: grafana: image: grafana/grafana:latest + logging: + driver: json-file + options: + max-size: 10m + max-file: 3 environment: - GF_PROVISIONING_DASHBOARDS_ENABLE=1 - GF_PROVISIONING_DASHBOARDS_PATH=/etc/grafana/provisioning/dashboards @@ -37,6 +47,11 @@ services: loki: image: grafana/loki:latest + logging: + driver: json-file + options: + max-size: 10m + max-file: 3 expose: - 3100 volumes: @@ -47,6 +62,11 @@ services: alloy: image: grafana/alloy:latest + logging: + driver: json-file + options: + max-size: 10m + max-file: 3 volumes: - ./config.alloy:/etc/alloy/config.alloy - /var/run/docker.sock:/var/run/docker.sock:ro @@ -61,6 +81,11 @@ services: node_exporter: image: prom/node-exporter:latest + logging: + driver: json-file + options: + max-size: 10m + max-file: 3 restart: unless-stopped pid: host volumes: diff --git a/services/postgres.yaml b/services/postgres.yaml index 714fb473f..6945b7efa 100644 --- a/services/postgres.yaml +++ b/services/postgres.yaml @@ -1,15 +1,15 @@ services: db: image: docker.io/postgres:15-alpine + logging: + driver: json-file + options: + max-size: 10m + max-file: 3 env_file: - ../config/prod.env environment: - TZ=Europe/Berlin - logging: - driver: json-file - options: - max-size: 5m - max-file: 5 volumes: - postgres-data:/var/lib/postgresql/data/ expose: diff --git a/services/powersync.yaml b/services/powersync.yaml index b279e5244..066e56965 100644 --- a/services/powersync.yaml +++ b/services/powersync.yaml @@ -6,6 +6,11 @@ services: restart: unless-stopped image: docker.io/journeyapps/powersync-service:latest + logging: + driver: json-file + options: + max-size: 10m + max-file: 3 # The unified service runs an API server and replication worker in the same container. # These services can be executed in different containers by using individual entry commands e.g. diff --git a/services/redis.yaml b/services/redis.yaml index 2bbb11e55..fd06f6edf 100644 --- a/services/redis.yaml +++ b/services/redis.yaml @@ -1,13 +1,13 @@ services: cache: image: docker.io/redis - expose: - - 6379 logging: driver: json-file options: - max-size: 5m - max-file: 5 + max-size: 10m + max-file: 3 + expose: + - 6379 volumes: - ../config/redis.conf:/usr/local/etc/redis/redis.conf # - redis-data:/data From 8c921be549e89a0c4b8488a9b8496dc260932d9b Mon Sep 17 00:00:00 2001 From: Roland Geider Date: Wed, 20 May 2026 16:15:09 +0200 Subject: [PATCH 51/53] Some tweaks for the postgres service --- services/postgres.yaml | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/services/postgres.yaml b/services/postgres.yaml index 6945b7efa..a90cef1a8 100644 --- a/services/postgres.yaml +++ b/services/postgres.yaml @@ -14,8 +14,15 @@ services: - postgres-data:/var/lib/postgresql/data/ expose: - 5432 - # "-c", "log_statement=all", "-c", "log_min_error_statement=DEBUG1" - command: [ "postgres", "-c", "wal_level=logical" ] + command: [ + "postgres", + "-c", "wal_level=logical", + "-c", "shared_buffers=256MB", + "-c", "effective_cache_size=768MB", + "-c", "work_mem=8MB", + "-c", "random_page_cost=1.1", + "-c", "max_connections=30" + ] healthcheck: test: ["CMD-SHELL", "pg_isready -U \"$$POSTGRES_USER\""] interval: 10s From 28dbaea68aef900a87ae3c1c83450a590b55042a Mon Sep 17 00:00:00 2001 From: Roland Geider Date: Wed, 20 May 2026 16:27:06 +0200 Subject: [PATCH 52/53] Also sync the exercise comments --- services/config-powersync/sync_rules.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/services/config-powersync/sync_rules.yaml b/services/config-powersync/sync_rules.yaml index 515f62f5e..26f08e688 100644 --- a/services/config-powersync/sync_rules.yaml +++ b/services/config-powersync/sync_rules.yaml @@ -20,6 +20,7 @@ streams: - SELECT * FROM exercises_exercise - SELECT * FROM exercises_translation - SELECT * FROM exercises_alias + - SELECT * FROM exercises_exercisecomment - SELECT * FROM exercises_muscle - SELECT * FROM exercises_exercise_muscles - SELECT * FROM exercises_exercise_muscles_secondary From a404602537e8a0d7fef847cad2c4377e0aeeafff Mon Sep 17 00:00:00 2001 From: Roland Geider Date: Fri, 22 May 2026 17:42:35 +0200 Subject: [PATCH 53/53] Also sync the user's profile --- services/config-powersync/sync_rules.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/services/config-powersync/sync_rules.yaml b/services/config-powersync/sync_rules.yaml index 26f08e688..d3de3ce66 100644 --- a/services/config-powersync/sync_rules.yaml +++ b/services/config-powersync/sync_rules.yaml @@ -73,6 +73,9 @@ streams: CAST(nutrition_nutritionplan.user_id AS TEXT) = auth.user_id() ) queries: + # User profile + - SELECT * FROM core_userprofile WHERE CAST(user_id AS TEXT) = auth.user_id() + # Weight - SELECT uuid AS id, weight, date, user_id FROM weight_weightentry WHERE CAST(user_id AS TEXT) = auth.user_id()