{
  "manifest_version": "1.0.0",
  "template": {
    "id": "87cd5594-aa4e-4e9e-b12d-bec804cb7e19",
    "slug": "safebucket",
    "name": "Safebucket",
    "description": "File transfer and sharing: send files via expiring links. WeTransfer, 2FA",
    "url": "https://railway.com/deploy/safebucket",
    "upstream": {
      "image": "ghcr.io/hmseeb/safebucket-railway-minio:latest"
    }
  },
  "status": "unvalidated",
  "validated_at": null,
  "success_rate_30d": null,
  "services": [
    {
      "name": "MinIO",
      "source": {
        "image": "ghcr.io/hmseeb/safebucket-railway-minio:latest"
      },
      "needs_volume": true,
      "volume_mount_path": "/data",
      "http": true
    },
    {
      "name": "Safebucket",
      "source": {
        "image": "ghcr.io/safebucket/safebucket:latest"
      },
      "needs_volume": false,
      "http": true
    },
    {
      "name": "Postgres",
      "source": {
        "image": "ghcr.io/railwayapp-templates/postgres-ssl:17"
      },
      "needs_volume": true,
      "volume_mount_path": "/var/lib/postgresql/data",
      "http": false
    }
  ],
  "required_inputs": [
    {
      "key": "PORT",
      "service": "MinIO",
      "description": "The port the file storage service listens on inside its container. Leave this alone.",
      "secret": false,
      "strategy": "default",
      "default": "9000"
    },
    {
      "key": "MINIO_ROOT_PASSWORD",
      "service": "MinIO",
      "description": "The admin password for your file storage. Generated fresh for your deployment. Safebucket picks it up automatically.",
      "secret": true,
      "strategy": "generate",
      "generate": "strong_password"
    },
    {
      "key": "GOGC",
      "service": "Safebucket",
      "description": "Keeps the server's memory use modest. Leave this alone.",
      "secret": false,
      "strategy": "default",
      "default": "50"
    },
    {
      "key": "PORT",
      "service": "Safebucket",
      "description": "The port the Safebucket server listens on inside its container. Leave this alone.",
      "secret": false,
      "strategy": "default",
      "default": "8080"
    },
    {
      "key": "APP__PORT",
      "service": "Safebucket",
      "description": "Same port, in the format Safebucket reads. Leave this alone.",
      "secret": false,
      "strategy": "default",
      "default": "8080"
    },
    {
      "key": "CACHE__TYPE",
      "service": "Safebucket",
      "description": "Rate limits and sessions are kept in the app's own memory. Fine for a single instance; switch to a Valkey service before scaling to multiple instances.",
      "secret": false,
      "strategy": "default",
      "default": "memory"
    },
    {
      "key": "APP__API_URL",
      "service": "Safebucket",
      "description": "The public web address of your Safebucket. Filled in automatically from this service's domain.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_domain"
    },
    {
      "key": "APP__PROFILE",
      "service": "Safebucket",
      "description": "Runs the API and background workers together in one service. Leave this alone.",
      "secret": false,
      "strategy": "default",
      "default": "default"
    },
    {
      "key": "APP__WEB_URL",
      "service": "Safebucket",
      "description": "Where the web app lives. Same address as the API because the UI is bundled. Filled in automatically.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_domain"
    },
    {
      "key": "EVENTS__TYPE",
      "service": "Safebucket",
      "description": "Background jobs are queued in the app's own memory. Fine for a single instance; switch to NATS JetStream before scaling to multiple instances.",
      "secret": false,
      "strategy": "default",
      "default": "memory"
    },
    {
      "key": "STORAGE__TYPE",
      "service": "Safebucket",
      "description": "Where uploaded files live. Points at the bundled MinIO service. Leave this alone.",
      "secret": false,
      "strategy": "default",
      "default": "minio"
    },
    {
      "key": "ACTIVITY__TYPE",
      "service": "Safebucket",
      "description": "Where the audit trail is stored. Files inside the container by default, which resets on each deploy. Switch to loki with a Loki service for a persistent audit trail.",
      "secret": false,
      "strategy": "default",
      "default": "filesystem"
    },
    {
      "key": "APP__LOG_LEVEL",
      "service": "Safebucket",
      "description": "How chatty the server logs are. Use debug when troubleshooting.",
      "secret": false,
      "strategy": "default",
      "default": "info"
    },
    {
      "key": "DATABASE__TYPE",
      "service": "Safebucket",
      "description": "Which kind of database to use. Leave this alone.",
      "secret": false,
      "strategy": "default",
      "default": "postgres"
    },
    {
      "key": "NOTIFIER__TYPE",
      "service": "Safebucket",
      "description": "Where invite and share emails go. By default they are written to files inside the container instead of being sent. To send real email, change this to smtp and add the NOTIFIER__SMTP__* settings from the README.",
      "secret": false,
      "strategy": "default",
      "default": "filesystem"
    },
    {
      "key": "APP__ADMIN_EMAIL",
      "service": "Safebucket",
      "description": "The email address for the first admin account. You log in with this after the deploy finishes.",
      "secret": false,
      "strategy": "ask_user"
    },
    {
      "key": "APP__MFA_REQUIRED",
      "service": "Safebucket",
      "description": "Set to true to force every user to set up two-factor authentication.",
      "secret": false,
      "strategy": "default",
      "default": "false"
    },
    {
      "key": "APP__TOKEN_SECRET",
      "service": "Safebucket",
      "description": "Signs login sessions. Generated fresh for your deployment. Never share it and never change it after launch.",
      "secret": true,
      "strategy": "generate",
      "generate": "random_base64_32"
    },
    {
      "key": "APP__ADMIN_PASSWORD",
      "service": "Safebucket",
      "description": "The password for the first admin account. Pick something strong; you can enable MFA after logging in.",
      "secret": true,
      "strategy": "generate",
      "generate": "strong_password"
    },
    {
      "key": "APP__ALLOWED_ORIGINS",
      "service": "Safebucket",
      "description": "Which websites are allowed to talk to your Safebucket from a browser. Defaults to your own domain, which is what you want.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_domain"
    },
    {
      "key": "APP__MAX_UPLOAD_SIZE",
      "service": "Safebucket",
      "description": "The largest allowed upload, in bytes. Defaults to 50 GB.",
      "secret": false,
      "strategy": "default",
      "default": "53687091200"
    },
    {
      "key": "APP__TRUSTED_PROXIES",
      "service": "Safebucket",
      "description": "Tells Safebucket to trust Railway's edge proxy so the audit trail records real visitor addresses instead of the proxy's.",
      "secret": false,
      "strategy": "default",
      "default": "0.0.0.0/0,::/0"
    },
    {
      "key": "AUTH__PROVIDERS__KEYS",
      "service": "Safebucket",
      "description": "Which login methods are enabled. Email and password by default; see the Safebucket docs to add single sign-on.",
      "secret": true,
      "strategy": "default",
      "default": "local"
    },
    {
      "key": "APP__MFA_ENCRYPTION_KEY",
      "service": "Safebucket",
      "description": "Encrypts users' two-factor authentication secrets. Must stay exactly 32 characters. Generated fresh; never change it after users enroll MFA.",
      "secret": true,
      "strategy": "generate",
      "generate": "random_base64_32"
    },
    {
      "key": "DATABASE__POSTGRES__HOST",
      "service": "Safebucket",
      "description": "The private address of the Postgres service. Filled in automatically.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_private_domain"
    },
    {
      "key": "DATABASE__POSTGRES__NAME",
      "service": "Safebucket",
      "description": "The database name. Copied automatically from the Postgres service.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "DATABASE__POSTGRES__PORT",
      "service": "Safebucket",
      "description": "The Postgres port. Leave this alone.",
      "secret": false,
      "strategy": "default",
      "default": "5432"
    },
    {
      "key": "DATABASE__POSTGRES__USER",
      "service": "Safebucket",
      "description": "The database account. Copied automatically from the Postgres service.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "STORAGE__MINIO__ENDPOINT",
      "service": "Safebucket",
      "description": "The private address the server uses to reach file storage. Filled in automatically.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_private_domain"
    },
    {
      "key": "APP__TRASH_RETENTION_DAYS",
      "service": "Safebucket",
      "description": "How many days deleted files stay in the trash before being removed for good.",
      "secret": false,
      "strategy": "default",
      "default": "7"
    },
    {
      "key": "STORAGE__MINIO__CLIENT_ID",
      "service": "Safebucket",
      "description": "The storage account name, baked into the MinIO image. Leave this alone.",
      "secret": false,
      "strategy": "default",
      "default": "safebucket"
    },
    {
      "key": "APP__STATIC_FILES__ENABLED",
      "service": "Safebucket",
      "description": "Serves the web app from this same service. Leave this alone.",
      "secret": false,
      "strategy": "default",
      "default": "true"
    },
    {
      "key": "DATABASE__POSTGRES__SSLMODE",
      "service": "Safebucket",
      "description": "Encrypts the database connection. The bundled Postgres supports this out of the box.",
      "secret": false,
      "strategy": "default",
      "default": "require"
    },
    {
      "key": "STORAGE__MINIO__BUCKET_NAME",
      "service": "Safebucket",
      "description": "The storage bucket files are kept in. The MinIO service creates it on first boot. Leave this alone.",
      "secret": false,
      "strategy": "default",
      "default": "safebucket"
    },
    {
      "key": "AUTH__PROVIDERS__LOCAL__NAME",
      "service": "Safebucket",
      "description": "Login provider setting. Leave this alone.",
      "secret": false,
      "strategy": "default",
      "default": "local"
    },
    {
      "key": "AUTH__PROVIDERS__LOCAL__TYPE",
      "service": "Safebucket",
      "description": "Login provider setting. Leave this alone.",
      "secret": false,
      "strategy": "default",
      "default": "local"
    },
    {
      "key": "DATABASE__POSTGRES__PASSWORD",
      "service": "Safebucket",
      "description": "The database password. Copied automatically from the Postgres service.",
      "secret": true,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "STORAGE__MINIO__CLIENT_SECRET",
      "service": "Safebucket",
      "description": "The password Safebucket uses to reach its file storage. Copied automatically from the MinIO service.",
      "secret": true,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "ACTIVITY__FILESYSTEM__DIRECTORY",
      "service": "Safebucket",
      "description": "Where the audit trail files are written. Leave this alone.",
      "secret": false,
      "strategy": "default",
      "default": "/app/data/activity"
    },
    {
      "key": "NOTIFIER__FILESYSTEM__DIRECTORY",
      "service": "Safebucket",
      "description": "Where unsent notification emails are written. Leave this alone.",
      "secret": false,
      "strategy": "default",
      "default": "/app/data/notifications"
    },
    {
      "key": "STORAGE__MINIO__EXTERNAL_ENDPOINT",
      "service": "Safebucket",
      "description": "The public address your browser uploads and downloads files through. Filled in automatically from the MinIO service's domain.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_domain"
    },
    {
      "key": "EVENTS__QUEUES__BUCKET_EVENTS__NAME",
      "service": "Safebucket",
      "description": "Internal queue name. Leave this alone.",
      "secret": false,
      "strategy": "default",
      "default": "safebucket-bucket-events"
    },
    {
      "key": "EVENTS__QUEUES__NOTIFICATIONS__NAME",
      "service": "Safebucket",
      "description": "Internal queue name. Leave this alone.",
      "secret": false,
      "strategy": "default",
      "default": "safebucket-notifications"
    },
    {
      "key": "EVENTS__QUEUES__OBJECT_DELETION__NAME",
      "service": "Safebucket",
      "description": "Internal queue name. Leave this alone.",
      "secret": false,
      "strategy": "default",
      "default": "safebucket-object-deletion"
    },
    {
      "key": "AUTH__PROVIDERS__LOCAL__SHARING__ALLOWED",
      "service": "Safebucket",
      "description": "Lets users share files with people outside your Safebucket.",
      "secret": false,
      "strategy": "default",
      "default": "true"
    },
    {
      "key": "PGDATA",
      "service": "Postgres",
      "description": "The folder on disk where the database keeps your data. A subdirectory of the mount, because the volume root contains a lost+found directory that Postgres refuses to initialize into. Leave this alone.",
      "secret": false,
      "strategy": "default",
      "default": "/var/lib/postgresql/data/pgdata"
    },
    {
      "key": "POSTGRES_DB",
      "service": "Postgres",
      "description": "The name of the database created on first launch.",
      "secret": false,
      "strategy": "default",
      "default": "safebucket"
    },
    {
      "key": "POSTGRES_USER",
      "service": "Postgres",
      "description": "The database account created on first launch.",
      "secret": false,
      "strategy": "default",
      "default": "safebucket"
    },
    {
      "key": "POSTGRES_PASSWORD",
      "service": "Postgres",
      "description": "The database password, generated fresh for your deployment. Never share it.",
      "secret": true,
      "strategy": "generate",
      "generate": "strong_password"
    }
  ],
  "deploy": {
    "mcp": {
      "server": "railway",
      "tool": "deploy_template",
      "args": {
        "template_code": "safebucket"
      }
    },
    "cli": "railway deploy --template safebucket",
    "api": {
      "method": "POST",
      "path": "/graphql/v2",
      "body": {
        "query": "mutation templateDeploy($input: TemplateDeployV2Input!) { templateDeployV2(input: $input) { projectId workflowId } }",
        "variables": {
          "input": {
            "templateId": "87cd5594-aa4e-4e9e-b12d-bec804cb7e19",
            "serializedConfig": {
              "buckets": {},
              "services": {
                "2b3303fb-a19d-4922-abf8-58e0d8ce24ee": {
                  "icon": null,
                  "name": "MinIO",
                  "deploy": {
                    "healthcheckPath": "/minio/health/live",
                    "restartPolicyType": "ON_FAILURE",
                    "restartPolicyMaxRetries": 10
                  },
                  "source": {
                    "image": "ghcr.io/hmseeb/safebucket-railway-minio:latest"
                  },
                  "variables": {
                    "PORT": {
                      "isOptional": false,
                      "description": "The port the file storage service listens on inside its container. Leave this alone.",
                      "defaultValue": "9000"
                    },
                    "MINIO_ROOT_PASSWORD": {
                      "isOptional": false,
                      "description": "The admin password for your file storage. Generated fresh for your deployment. Safebucket picks it up automatically.",
                      "defaultValue": "{{MINIO_ROOT_PASSWORD}}"
                    }
                  },
                  "networking": {
                    "serviceDomains": {
                      "<hasDomain>": {}
                    }
                  },
                  "volumeMounts": {
                    "62342776-705f-4ad0-8311-91579de757c9": {
                      "mountPath": "/data"
                    }
                  }
                },
                "4863647e-a580-477b-afc5-2d428bd42eaa": {
                  "icon": "https://raw.githubusercontent.com/safebucket/safebucket/main/web/public/logo512.png",
                  "name": "Safebucket",
                  "deploy": {
                    "healthcheckPath": "/",
                    "restartPolicyType": "ON_FAILURE",
                    "restartPolicyMaxRetries": 10
                  },
                  "source": {
                    "image": "ghcr.io/safebucket/safebucket:latest"
                  },
                  "variables": {
                    "GOGC": {
                      "isOptional": false,
                      "description": "Keeps the server's memory use modest. Leave this alone.",
                      "defaultValue": "50"
                    },
                    "PORT": {
                      "isOptional": false,
                      "description": "The port the Safebucket server listens on inside its container. Leave this alone.",
                      "defaultValue": "8080"
                    },
                    "APP__PORT": {
                      "isOptional": false,
                      "description": "Same port, in the format Safebucket reads. Leave this alone.",
                      "defaultValue": "8080"
                    },
                    "CACHE__TYPE": {
                      "isOptional": false,
                      "description": "Rate limits and sessions are kept in the app's own memory. Fine for a single instance; switch to a Valkey service before scaling to multiple instances.",
                      "defaultValue": "memory"
                    },
                    "APP__API_URL": {
                      "isOptional": false,
                      "description": "The public web address of your Safebucket. Filled in automatically from this service's domain.",
                      "defaultValue": "https://${{RAILWAY_PUBLIC_DOMAIN}}"
                    },
                    "APP__PROFILE": {
                      "isOptional": false,
                      "description": "Runs the API and background workers together in one service. Leave this alone.",
                      "defaultValue": "default"
                    },
                    "APP__WEB_URL": {
                      "isOptional": false,
                      "description": "Where the web app lives. Same address as the API because the UI is bundled. Filled in automatically.",
                      "defaultValue": "https://${{RAILWAY_PUBLIC_DOMAIN}}"
                    },
                    "EVENTS__TYPE": {
                      "isOptional": false,
                      "description": "Background jobs are queued in the app's own memory. Fine for a single instance; switch to NATS JetStream before scaling to multiple instances.",
                      "defaultValue": "memory"
                    },
                    "STORAGE__TYPE": {
                      "isOptional": false,
                      "description": "Where uploaded files live. Points at the bundled MinIO service. Leave this alone.",
                      "defaultValue": "minio"
                    },
                    "ACTIVITY__TYPE": {
                      "isOptional": false,
                      "description": "Where the audit trail is stored. Files inside the container by default, which resets on each deploy. Switch to loki with a Loki service for a persistent audit trail.",
                      "defaultValue": "filesystem"
                    },
                    "APP__LOG_LEVEL": {
                      "isOptional": false,
                      "description": "How chatty the server logs are. Use debug when troubleshooting.",
                      "defaultValue": "info"
                    },
                    "DATABASE__TYPE": {
                      "isOptional": false,
                      "description": "Which kind of database to use. Leave this alone.",
                      "defaultValue": "postgres"
                    },
                    "NOTIFIER__TYPE": {
                      "isOptional": false,
                      "description": "Where invite and share emails go. By default they are written to files inside the container instead of being sent. To send real email, change this to smtp and add the NOTIFIER__SMTP__* settings from the README.",
                      "defaultValue": "filesystem"
                    },
                    "APP__ADMIN_EMAIL": {
                      "isOptional": false,
                      "description": "The email address for the first admin account. You log in with this after the deploy finishes.",
                      "defaultValue": "{{APP__ADMIN_EMAIL}}"
                    },
                    "APP__MFA_REQUIRED": {
                      "isOptional": false,
                      "description": "Set to true to force every user to set up two-factor authentication.",
                      "defaultValue": "false"
                    },
                    "APP__TOKEN_SECRET": {
                      "isOptional": false,
                      "description": "Signs login sessions. Generated fresh for your deployment. Never share it and never change it after launch.",
                      "defaultValue": "{{APP__TOKEN_SECRET}}"
                    },
                    "APP__ADMIN_PASSWORD": {
                      "isOptional": false,
                      "description": "The password for the first admin account. Pick something strong; you can enable MFA after logging in.",
                      "defaultValue": "{{APP__ADMIN_PASSWORD}}"
                    },
                    "APP__ALLOWED_ORIGINS": {
                      "isOptional": false,
                      "description": "Which websites are allowed to talk to your Safebucket from a browser. Defaults to your own domain, which is what you want.",
                      "defaultValue": "https://${{RAILWAY_PUBLIC_DOMAIN}}"
                    },
                    "APP__MAX_UPLOAD_SIZE": {
                      "isOptional": false,
                      "description": "The largest allowed upload, in bytes. Defaults to 50 GB.",
                      "defaultValue": "53687091200"
                    },
                    "APP__TRUSTED_PROXIES": {
                      "isOptional": false,
                      "description": "Tells Safebucket to trust Railway's edge proxy so the audit trail records real visitor addresses instead of the proxy's.",
                      "defaultValue": "0.0.0.0/0,::/0"
                    },
                    "AUTH__PROVIDERS__KEYS": {
                      "isOptional": false,
                      "description": "Which login methods are enabled. Email and password by default; see the Safebucket docs to add single sign-on.",
                      "defaultValue": "local"
                    },
                    "APP__MFA_ENCRYPTION_KEY": {
                      "isOptional": false,
                      "description": "Encrypts users' two-factor authentication secrets. Must stay exactly 32 characters. Generated fresh; never change it after users enroll MFA.",
                      "defaultValue": "{{APP__MFA_ENCRYPTION_KEY}}"
                    },
                    "DATABASE__POSTGRES__HOST": {
                      "isOptional": false,
                      "description": "The private address of the Postgres service. Filled in automatically.",
                      "defaultValue": "${{Postgres.RAILWAY_PRIVATE_DOMAIN}}"
                    },
                    "DATABASE__POSTGRES__NAME": {
                      "isOptional": false,
                      "description": "The database name. Copied automatically from the Postgres service.",
                      "defaultValue": "${{Postgres.POSTGRES_DB}}"
                    },
                    "DATABASE__POSTGRES__PORT": {
                      "isOptional": false,
                      "description": "The Postgres port. Leave this alone.",
                      "defaultValue": "5432"
                    },
                    "DATABASE__POSTGRES__USER": {
                      "isOptional": false,
                      "description": "The database account. Copied automatically from the Postgres service.",
                      "defaultValue": "${{Postgres.POSTGRES_USER}}"
                    },
                    "STORAGE__MINIO__ENDPOINT": {
                      "isOptional": false,
                      "description": "The private address the server uses to reach file storage. Filled in automatically.",
                      "defaultValue": "${{MinIO.RAILWAY_PRIVATE_DOMAIN}}:9000"
                    },
                    "APP__TRASH_RETENTION_DAYS": {
                      "isOptional": false,
                      "description": "How many days deleted files stay in the trash before being removed for good.",
                      "defaultValue": "7"
                    },
                    "STORAGE__MINIO__CLIENT_ID": {
                      "isOptional": false,
                      "description": "The storage account name, baked into the MinIO image. Leave this alone.",
                      "defaultValue": "safebucket"
                    },
                    "APP__STATIC_FILES__ENABLED": {
                      "isOptional": false,
                      "description": "Serves the web app from this same service. Leave this alone.",
                      "defaultValue": "true"
                    },
                    "DATABASE__POSTGRES__SSLMODE": {
                      "isOptional": false,
                      "description": "Encrypts the database connection. The bundled Postgres supports this out of the box.",
                      "defaultValue": "require"
                    },
                    "STORAGE__MINIO__BUCKET_NAME": {
                      "isOptional": false,
                      "description": "The storage bucket files are kept in. The MinIO service creates it on first boot. Leave this alone.",
                      "defaultValue": "safebucket"
                    },
                    "AUTH__PROVIDERS__LOCAL__NAME": {
                      "isOptional": false,
                      "description": "Login provider setting. Leave this alone.",
                      "defaultValue": "local"
                    },
                    "AUTH__PROVIDERS__LOCAL__TYPE": {
                      "isOptional": false,
                      "description": "Login provider setting. Leave this alone.",
                      "defaultValue": "local"
                    },
                    "DATABASE__POSTGRES__PASSWORD": {
                      "isOptional": false,
                      "description": "The database password. Copied automatically from the Postgres service.",
                      "defaultValue": "${{Postgres.POSTGRES_PASSWORD}}"
                    },
                    "STORAGE__MINIO__CLIENT_SECRET": {
                      "isOptional": false,
                      "description": "The password Safebucket uses to reach its file storage. Copied automatically from the MinIO service.",
                      "defaultValue": "${{MinIO.MINIO_ROOT_PASSWORD}}"
                    },
                    "ACTIVITY__FILESYSTEM__DIRECTORY": {
                      "isOptional": false,
                      "description": "Where the audit trail files are written. Leave this alone.",
                      "defaultValue": "/app/data/activity"
                    },
                    "NOTIFIER__FILESYSTEM__DIRECTORY": {
                      "isOptional": false,
                      "description": "Where unsent notification emails are written. Leave this alone.",
                      "defaultValue": "/app/data/notifications"
                    },
                    "STORAGE__MINIO__EXTERNAL_ENDPOINT": {
                      "isOptional": false,
                      "description": "The public address your browser uploads and downloads files through. Filled in automatically from the MinIO service's domain.",
                      "defaultValue": "https://${{MinIO.RAILWAY_PUBLIC_DOMAIN}}"
                    },
                    "EVENTS__QUEUES__BUCKET_EVENTS__NAME": {
                      "isOptional": false,
                      "description": "Internal queue name. Leave this alone.",
                      "defaultValue": "safebucket-bucket-events"
                    },
                    "EVENTS__QUEUES__NOTIFICATIONS__NAME": {
                      "isOptional": false,
                      "description": "Internal queue name. Leave this alone.",
                      "defaultValue": "safebucket-notifications"
                    },
                    "EVENTS__QUEUES__OBJECT_DELETION__NAME": {
                      "isOptional": false,
                      "description": "Internal queue name. Leave this alone.",
                      "defaultValue": "safebucket-object-deletion"
                    },
                    "AUTH__PROVIDERS__LOCAL__SHARING__ALLOWED": {
                      "isOptional": false,
                      "description": "Lets users share files with people outside your Safebucket.",
                      "defaultValue": "true"
                    }
                  },
                  "networking": {
                    "serviceDomains": {
                      "<hasDomain>": {}
                    }
                  }
                },
                "4e61c489-ca84-4f2a-92ba-110b045ed48d": {
                  "icon": null,
                  "name": "Postgres",
                  "deploy": {
                    "restartPolicyType": "ON_FAILURE",
                    "restartPolicyMaxRetries": 10
                  },
                  "source": {
                    "image": "ghcr.io/railwayapp-templates/postgres-ssl:17"
                  },
                  "variables": {
                    "PGDATA": {
                      "isOptional": false,
                      "description": "The folder on disk where the database keeps your data. A subdirectory of the mount, because the volume root contains a lost+found directory that Postgres refuses to initialize into. Leave this alone.",
                      "defaultValue": "/var/lib/postgresql/data/pgdata"
                    },
                    "POSTGRES_DB": {
                      "isOptional": false,
                      "description": "The name of the database created on first launch.",
                      "defaultValue": "safebucket"
                    },
                    "POSTGRES_USER": {
                      "isOptional": false,
                      "description": "The database account created on first launch.",
                      "defaultValue": "safebucket"
                    },
                    "POSTGRES_PASSWORD": {
                      "isOptional": false,
                      "description": "The database password, generated fresh for your deployment. Never share it.",
                      "defaultValue": "{{POSTGRES_PASSWORD}}"
                    }
                  },
                  "volumeMounts": {
                    "3f008444-86a8-45a7-a646-e67dacb2757a": {
                      "mountPath": "/var/lib/postgresql/data"
                    }
                  },
                  "haTemplateCode": "postgres-ha",
                  "haConversionConfig": {
                    "edge": {
                      "label": "Reverse Proxy",
                      "options": [
                        2,
                        3,
                        4,
                        5
                      ],
                      "nodeLabel": "HAProxy",
                      "description": "Routes traffic to the primary",
                      "defaultValue": 3
                    },
                    "replica": {
                      "label": "Replicas",
                      "options": [
                        2,
                        3,
                        4,
                        5,
                        6,
                        7
                      ],
                      "nodeLabel": "Postgres",
                      "description": "Streaming replicas for automatic failover",
                      "defaultValue": 2
                    },
                    "internal": {
                      "label": "Coordinator Nodes",
                      "options": [
                        3,
                        5,
                        7,
                        9
                      ],
                      "nodeLabel": "etcd",
                      "defaultValue": 3
                    },
                    "description": "This will convert your Postgres database to an HA cluster with Patroni failover and etcd consensus."
                  }
                }
              }
            }
          }
        }
      }
    }
  },
  "post_deploy": {
    "healthcheck": {
      "service": "MinIO",
      "method": "GET",
      "path": "/minio/health/live",
      "expect_status": 200
    }
  },
  "resources": {
    "expected_services": 3,
    "needs_volume": true
  },
  "generated_at": "2026-09-10T10:14:45.332Z",
  "generator_version": "0.1.0"
}
