Skip to content

Backend Operations

Eric Slutz edited this page Jul 29, 2026 · 7 revisions

Backend Operations

PumpSync.backend runs the same ASP.NET Core container image for hosted service and self-host/demo distribution, with different configuration.

Hosted Mode

Hosted PumpSync runs on Azure Container Apps with Azure Table Storage.

  • PumpSync__BackendMode=Hosted
  • PumpSync__DataSourceMode=TandemSource
  • PumpSync__StorageProvider=AzureTableStorage
  • Azure Container Apps scale minimum: 0
  • Public app base URL includes /api
  • App Store Server Notification URL is /api/v1/app-store/notifications

Infrastructure

infra/bicep/main.subscription.bicep creates or updates:

  • Resource group.
  • Azure Container Apps managed environment.
  • Backend container app (with HTTP liveness/readiness probes against /health).
  • User-assigned managed identity.
  • Key Vault.
  • Application Insights and Log Analytics.
  • Storage account and Table Storage tables.
  • Optional managed identity role assignments.

An App Configuration store from an earlier iteration is no longer part of the template; nothing reads or writes it, so any live instance can be deleted.

Build the templates:

az bicep build --file infra/bicep/main.bicep
az bicep build --file infra/bicep/main.subscription.bicep

Deploy with the GitHub Deploy Backend workflow. The workflow restores, builds, tests, builds and pushes the Docker image to GitHub Container Registry, deploys Bicep with that image, runs smoke tests, and prints the hosted API base URL and App Store Server Notification URL.

Image Registry Policy

Image use Registry Visibility Notes
Hosted production/nonprod API GitHub Container Registry Private ghcr.io/eslutz/pumpsync-backend. The deploy workflow deploys the immutable commit-SHA tag to Container Apps and also pushes floating nonprod-latest/prod-latest tags; a bare latest is pushed only on prod deploys.
Self-host/demo distribution image GitHub Container Registry Public ghcr.io/eslutz/pumpsync-backend-self-hosted, published by the Publish Self-Host Image workflow (SHA + latest) on every backend change that lands on main. Used by Docker self-hosters and the demo Container App.

The iOS app does not choose a registry. It only stores a backend base URL.

Hosted Environment Validation

Public docs intentionally avoid listing live hosted backend endpoint values. Use the Deploy Backend workflow output, Azure Container Apps configuration, or trusted operator notes to retrieve the current hosted base URL.

The Container App runs the commit-SHA image tag printed by the deploy workflow, not :latest.

Smoke test:

curl --fail <hosted-api-base-url>/v1/capabilities
curl --silent --output /tmp/status.json --write-out '%{http_code}' <hosted-api-base-url>/v1/status

The unauthenticated status call should return 401.

Hosted Synthetic Demo

Hosted demo API base URL:

https://demo.pumpsync.ericslutz.dev/api

Current demo Container App recorded in backend docs:

ca-pumpsync-demo-api

Current demo image recorded in backend docs:

ghcr.io/eslutz/pumpsync-backend-self-hosted:latest

The demo Container App pulls the public self-host/demo GHCR image without registry credentials.

Private GHCR Pull Token

Hosted Container Apps pulls from private GitHub Container Registry with a classic GitHub token that has only read:packages.

Do not grant:

  • repo
  • write:packages
  • delete:packages

The runtime token is stored in Key Vault as GitHubContainerRegistry--PullToken and exposed to Container Apps through a Key Vault-backed secret named ghcr-pull-token.

Data Deletion Tooling

The data deletion tool is in tools/PumpSync.DataDeletionRequest.

Build:

dotnet build tools/PumpSync.DataDeletionRequest/PumpSync.DataDeletionRequest.csproj

Hosted dry run:

dotnet run --project tools/PumpSync.DataDeletionRequest -- \
  --installation-id <installation-id> \
  --environment nonprod

Hosted execute:

DataDeletion__AuditHashSalt=<salt> \
dotnet run --project tools/PumpSync.DataDeletionRequest -- \
  --installation-id <installation-id> \
  --environment nonprod \
  --execute

Use --environment prod for production. Configure Azure storage with AzureStorage__AccountName plus Azure CLI/managed identity credentials, or with AzureStorage__ConnectionString.

Self-host execution uses SQLite configuration and should only run after backing up the SQLite database.

Clone this wiki locally