{
  "manifest_version": "1.0.0",
  "template": {
    "id": "025672ff-d1c6-45a6-b208-2005341a1ee7",
    "slug": "workadventure",
    "name": "WorkAdventure",
    "description": "Virtual office with proximity video chat on a customizable 2D map",
    "url": "https://railway.com/deploy/workadventure",
    "upstream": {
      "repo_url": "https://github.com/sukrutnrvd/workadventure-railway"
    }
  },
  "status": "unvalidated",
  "validated_at": null,
  "success_rate_30d": null,
  "services": [
    {
      "name": "uploader",
      "source": {
        "image": "thecodingmachine/workadventure-uploader:v1.34.4"
      },
      "needs_volume": false,
      "http": false
    },
    {
      "name": "back",
      "source": {
        "image": "thecodingmachine/workadventure-back:v1.34.4"
      },
      "needs_volume": false,
      "http": false
    },
    {
      "name": "Redis",
      "source": {
        "image": "redis:8.2"
      },
      "needs_volume": true,
      "volume_mount_path": "/data",
      "http": false
    },
    {
      "name": "icon",
      "source": {
        "image": "matthiasluedtke/iconserver:v3.21.0"
      },
      "needs_volume": false,
      "http": false
    },
    {
      "name": "play",
      "source": {
        "image": "thecodingmachine/workadventure-play:v1.34.4"
      },
      "needs_volume": false,
      "http": false
    },
    {
      "name": "mapstorage",
      "source": {
        "image": "thecodingmachine/workadventure-map-storage:v1.34.4"
      },
      "needs_volume": true,
      "volume_mount_path": "/maps",
      "http": false
    },
    {
      "name": "proxy",
      "source": {
        "repo": "https://github.com/sukrutnrvd/workadventure-railway"
      },
      "needs_volume": false,
      "http": true
    }
  ],
  "required_inputs": [
    {
      "key": "REDIS_HOST",
      "service": "uploader",
      "description": "Uploaded chat files are stored in Redis when no S3 bucket is configured",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "REDIS_PORT",
      "service": "uploader",
      "description": "Redis port",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "UPLOADER_URL",
      "service": "uploader",
      "description": "Public URL of the upload service",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_domain"
    },
    {
      "key": "REDIS_PASSWORD",
      "service": "uploader",
      "description": "Redis password",
      "secret": true,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "ENABLE_CHAT_UPLOAD",
      "service": "uploader",
      "description": "Allows sending files in the chat; must match play and back",
      "secret": false,
      "strategy": "default",
      "default": "true"
    },
    {
      "key": "UPLOAD_MAX_FILESIZE",
      "service": "uploader",
      "description": "Maximum upload size in bytes (10485760 = 10 MB)",
      "secret": false,
      "strategy": "default",
      "default": "10485760"
    },
    {
      "key": "PLAY_URL",
      "service": "back",
      "description": "Public URL of the app",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_domain"
    },
    {
      "key": "JITSI_URL",
      "service": "back",
      "description": "Jitsi server for meeting room areas; the public server limits embedded calls to 5 minutes",
      "secret": false,
      "strategy": "default",
      "default": "meet.jit.si"
    },
    {
      "key": "REDIS_HOST",
      "service": "back",
      "description": "Redis host on the private network",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "REDIS_PORT",
      "service": "back",
      "description": "Redis port",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "SECRET_KEY",
      "service": "back",
      "description": "Shared secret for signing tokens; play and mapstorage reference this value",
      "secret": true,
      "strategy": "generate",
      "generate": "random_base64_32"
    },
    {
      "key": "ENABLE_CHAT",
      "service": "back",
      "description": "Enables the proximity chat (messages are not stored)",
      "secret": false,
      "strategy": "default",
      "default": "true"
    },
    {
      "key": "MAX_PER_GROUP",
      "service": "back",
      "description": "Maximum number of people in one proximity video bubble",
      "secret": false,
      "strategy": "default",
      "default": "4"
    },
    {
      "key": "REDIS_PASSWORD",
      "service": "back",
      "description": "Redis password",
      "secret": true,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "MAP_STORAGE_URL",
      "service": "back",
      "description": "gRPC address of the map storage service",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_private_domain"
    },
    {
      "key": "ENABLE_MAP_EDITOR",
      "service": "back",
      "description": "In-game map editor; keep off while there are no personal logins, or anyone could edit maps",
      "secret": false,
      "strategy": "default",
      "default": "false"
    },
    {
      "key": "ENABLE_CHAT_UPLOAD",
      "service": "back",
      "description": "Allows sending files in the chat",
      "secret": false,
      "strategy": "default",
      "default": "true"
    },
    {
      "key": "PUBLIC_MAP_STORAGE_URL",
      "service": "back",
      "description": "Map storage as seen by browsers",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_domain"
    },
    {
      "key": "INTERNAL_MAP_STORAGE_URL",
      "service": "back",
      "description": "Map storage over the private network",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_private_domain"
    },
    {
      "key": "STORE_VARIABLES_FOR_LOCAL_MAPS",
      "service": "back",
      "description": "Keeps map variables (e.g. door states) in Redis across restarts",
      "secret": false,
      "strategy": "default",
      "default": "true"
    },
    {
      "key": "REDISHOST",
      "service": "Redis",
      "description": "Redis host on Railway's private network; other services reference this value",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_private_domain"
    },
    {
      "key": "REDISPORT",
      "service": "Redis",
      "description": "Port Redis listens on",
      "secret": false,
      "strategy": "default",
      "default": "6379"
    },
    {
      "key": "REDISUSER",
      "service": "Redis",
      "description": "Redis username; \"default\" is the built-in user that the password applies to",
      "secret": false,
      "strategy": "default",
      "default": "default"
    },
    {
      "key": "REDIS_URL",
      "service": "Redis",
      "description": "Full connection string over the private network",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "REDISPASSWORD",
      "service": "Redis",
      "description": "Password for connecting, mirrors REDIS_PASSWORD; referenced by play, back and uploader",
      "secret": true,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "REDIS_PASSWORD",
      "service": "Redis",
      "description": "Password Redis requires, 32 random letters generated per deploy",
      "secret": true,
      "strategy": "generate",
      "generate": "strong_password"
    },
    {
      "key": "PORT",
      "service": "icon",
      "description": "Port the favicon service listens on; set explicitly because Railway may inject a different PORT",
      "secret": false,
      "strategy": "default",
      "default": "8080"
    },
    {
      "key": "API_URL",
      "service": "play",
      "description": "gRPC address of the back service",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_private_domain"
    },
    {
      "key": "ICON_URL",
      "service": "play",
      "description": "Path of the favicon service behind the proxy",
      "secret": false,
      "strategy": "default",
      "default": "/icon"
    },
    {
      "key": "FRONT_URL",
      "service": "play",
      "description": "Path of the game front end",
      "secret": false,
      "strategy": "default",
      "default": "/"
    },
    {
      "key": "JITSI_URL",
      "service": "play",
      "description": "Jitsi server for meeting room areas; must match the back service",
      "secret": false,
      "strategy": "default",
      "default": "meet.jit.si"
    },
    {
      "key": "PUSHER_URL",
      "service": "play",
      "description": "Public URL of the app, with trailing slash",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_domain"
    },
    {
      "key": "REDIS_HOST",
      "service": "play",
      "description": "Redis host on the private network",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "REDIS_PORT",
      "service": "play",
      "description": "Redis port",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "SECRET_KEY",
      "service": "play",
      "description": "Same secret as the back service",
      "secret": true,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "ENABLE_CHAT",
      "service": "play",
      "description": "Enables the proximity chat (messages are not stored)",
      "secret": false,
      "strategy": "default",
      "default": "true"
    },
    {
      "key": "UPLOADER_URL",
      "service": "play",
      "description": "Path of the chat upload service behind the proxy",
      "secret": false,
      "strategy": "default",
      "default": "/uploader"
    },
    {
      "key": "MAX_PER_GROUP",
      "service": "play",
      "description": "Maximum number of people in one proximity video bubble; must match the back service",
      "secret": false,
      "strategy": "default",
      "default": "4"
    },
    {
      "key": "REDIS_PASSWORD",
      "service": "play",
      "description": "Redis password",
      "secret": true,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "START_ROOM_URL",
      "service": "play",
      "description": "Map visitors land on; for an uploaded map use a path like /~/office.wam",
      "secret": false,
      "strategy": "default",
      "default": "/_/global/workadventure.github.io/map-starter-kit/office.tmj"
    },
    {
      "key": "DISABLE_ANONYMOUS",
      "service": "play",
      "description": "Keep false; true only works with an OpenID Connect provider configured",
      "secret": false,
      "strategy": "default",
      "default": "false"
    },
    {
      "key": "ENABLE_MAP_EDITOR",
      "service": "play",
      "description": "In-game map editor; must match the back service",
      "secret": false,
      "strategy": "default",
      "default": "false"
    },
    {
      "key": "ENABLE_CHAT_UPLOAD",
      "service": "play",
      "description": "Allows sending files in the chat",
      "secret": false,
      "strategy": "default",
      "default": "true"
    },
    {
      "key": "MAX_USERNAME_LENGTH",
      "service": "play",
      "description": "Maximum length of player names",
      "secret": false,
      "strategy": "default",
      "default": "10"
    },
    {
      "key": "MAP_STORAGE_API_TOKEN",
      "service": "play",
      "description": "Token play and mapstorage use to call each other; same as the shared secret",
      "secret": true,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "PUBLIC_MAP_STORAGE_URL",
      "service": "play",
      "description": "Map storage as seen by browsers",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_domain"
    },
    {
      "key": "INTERNAL_MAP_STORAGE_URL",
      "service": "play",
      "description": "Map storage over the private network",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_private_domain"
    },
    {
      "key": "API_URL",
      "service": "mapstorage",
      "description": "gRPC address of the back service",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_private_domain"
    },
    {
      "key": "PUSHER_URL",
      "service": "mapstorage",
      "description": "Public URL of the app, with trailing slash",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_domain"
    },
    {
      "key": "SECRET_KEY",
      "service": "mapstorage",
      "description": "Same secret as the back service",
      "secret": true,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "PATH_PREFIX",
      "service": "mapstorage",
      "description": "Path the proxy serves map storage under",
      "secret": false,
      "strategy": "default",
      "default": "/map-storage"
    },
    {
      "key": "AUTHENTICATION_USER",
      "service": "mapstorage",
      "description": "Username for the map management page",
      "secret": false,
      "strategy": "default",
      "default": "admin"
    },
    {
      "key": "AUTHENTICATION_TOKEN",
      "service": "mapstorage",
      "description": "API key to enter in the map-starter-kit upload settings",
      "secret": true,
      "strategy": "generate",
      "generate": "random_base64_32"
    },
    {
      "key": "MAP_STORAGE_API_TOKEN",
      "service": "mapstorage",
      "description": "Token play and mapstorage use to call each other; same as the shared secret",
      "secret": true,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "ENTITY_COLLECTION_URLS",
      "service": "mapstorage",
      "description": "Furniture catalogs offered in the map editor",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_domain"
    },
    {
      "key": "AUTHENTICATION_PASSWORD",
      "service": "mapstorage",
      "description": "Password for the map management page; separate from the site password",
      "secret": true,
      "strategy": "generate",
      "generate": "strong_password"
    },
    {
      "key": "ENABLE_BASIC_AUTHENTICATION",
      "service": "mapstorage",
      "description": "Protects the map management page at /map-storage/ with a username and password",
      "secret": false,
      "strategy": "default",
      "default": "true"
    },
    {
      "key": "ENABLE_BEARER_AUTHENTICATION",
      "service": "mapstorage",
      "description": "Lets the map-starter-kit upload command authenticate with an API key",
      "secret": false,
      "strategy": "default",
      "default": "true"
    },
    {
      "key": "PORT",
      "service": "proxy",
      "description": "Port Caddy listens on; must match the public domain's target port",
      "secret": false,
      "strategy": "default",
      "default": "8080"
    },
    {
      "key": "BACK_HOST",
      "service": "proxy",
      "description": "Private hostname of the back service, served under /api",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_private_domain"
    },
    {
      "key": "ICON_HOST",
      "service": "proxy",
      "description": "Private hostname of the favicon service, served under /icon",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_private_domain"
    },
    {
      "key": "PLAY_HOST",
      "service": "proxy",
      "description": "Private hostname of the play service (game front end and WebSockets)",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_private_domain"
    },
    {
      "key": "ACCESS_USER",
      "service": "proxy",
      "description": "Username everyone enters to open the site; letters, digits, '.', '_' and '-' only",
      "secret": false,
      "strategy": "default",
      "default": "workadventure"
    },
    {
      "key": "UPLOADER_HOST",
      "service": "proxy",
      "description": "Private hostname of the chat upload service, served under /uploader",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_private_domain"
    },
    {
      "key": "ACCESS_PASSWORD",
      "service": "proxy",
      "description": "Shared password for the site; changing it signs everyone out; leave empty to make the site public",
      "secret": true,
      "strategy": "generate",
      "generate": "strong_password"
    },
    {
      "key": "MAP_STORAGE_HOST",
      "service": "proxy",
      "description": "Private hostname of the map storage service, served under /map-storage",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_private_domain"
    },
    {
      "key": "ACCESS_COOKIE_MAX_AGE",
      "service": "proxy",
      "description": "How long a login lasts in the same browser, in seconds (2592000 = 30 days)",
      "secret": false,
      "strategy": "default",
      "default": "2592000"
    }
  ],
  "deploy": {
    "mcp": {
      "server": "railway",
      "tool": "deploy_template",
      "args": {
        "template_code": "workadventure"
      }
    },
    "cli": "railway deploy --template workadventure",
    "api": {
      "method": "POST",
      "path": "/graphql/v2",
      "body": {
        "query": "mutation templateDeploy($input: TemplateDeployV2Input!) { templateDeployV2(input: $input) { projectId workflowId } }",
        "variables": {
          "input": {
            "templateId": "025672ff-d1c6-45a6-b208-2005341a1ee7",
            "serializedConfig": {
              "buckets": {},
              "services": {
                "204bd2d8-3c80-44e3-b94f-122a17b17ba3": {
                  "icon": null,
                  "name": "uploader",
                  "deploy": {
                    "startCommand": null,
                    "healthcheckPath": null,
                    "restartPolicyType": "ON_FAILURE",
                    "restartPolicyMaxRetries": 10
                  },
                  "source": {
                    "image": "thecodingmachine/workadventure-uploader:v1.34.4"
                  },
                  "variables": {
                    "REDIS_HOST": {
                      "isOptional": false,
                      "description": "Uploaded chat files are stored in Redis when no S3 bucket is configured",
                      "defaultValue": "${{Redis.REDISHOST}}"
                    },
                    "REDIS_PORT": {
                      "isOptional": false,
                      "description": "Redis port",
                      "defaultValue": "${{Redis.REDISPORT}}"
                    },
                    "UPLOADER_URL": {
                      "isOptional": false,
                      "description": "Public URL of the upload service",
                      "defaultValue": "https://${{proxy.RAILWAY_PUBLIC_DOMAIN}}/uploader"
                    },
                    "REDIS_PASSWORD": {
                      "isOptional": false,
                      "description": "Redis password",
                      "defaultValue": "${{Redis.REDISPASSWORD}}"
                    },
                    "ENABLE_CHAT_UPLOAD": {
                      "isOptional": false,
                      "description": "Allows sending files in the chat; must match play and back",
                      "defaultValue": "true"
                    },
                    "UPLOAD_MAX_FILESIZE": {
                      "isOptional": false,
                      "description": "Maximum upload size in bytes (10485760 = 10 MB)",
                      "defaultValue": "10485760"
                    }
                  }
                },
                "49872426-c344-414c-bd43-dfb20fcb6b48": {
                  "icon": null,
                  "name": "back",
                  "deploy": {
                    "startCommand": null,
                    "healthcheckPath": null,
                    "restartPolicyType": "ON_FAILURE",
                    "restartPolicyMaxRetries": 10
                  },
                  "source": {
                    "image": "thecodingmachine/workadventure-back:v1.34.4"
                  },
                  "variables": {
                    "PLAY_URL": {
                      "isOptional": false,
                      "description": "Public URL of the app",
                      "defaultValue": "https://${{proxy.RAILWAY_PUBLIC_DOMAIN}}"
                    },
                    "JITSI_URL": {
                      "isOptional": false,
                      "description": "Jitsi server for meeting room areas; the public server limits embedded calls to 5 minutes",
                      "defaultValue": "meet.jit.si"
                    },
                    "REDIS_HOST": {
                      "isOptional": false,
                      "description": "Redis host on the private network",
                      "defaultValue": "${{Redis.REDISHOST}}"
                    },
                    "REDIS_PORT": {
                      "isOptional": false,
                      "description": "Redis port",
                      "defaultValue": "${{Redis.REDISPORT}}"
                    },
                    "SECRET_KEY": {
                      "isOptional": false,
                      "description": "Shared secret for signing tokens; play and mapstorage reference this value",
                      "defaultValue": "{{SECRET_KEY}}"
                    },
                    "ENABLE_CHAT": {
                      "isOptional": false,
                      "description": "Enables the proximity chat (messages are not stored)",
                      "defaultValue": "true"
                    },
                    "MAX_PER_GROUP": {
                      "isOptional": false,
                      "description": "Maximum number of people in one proximity video bubble",
                      "defaultValue": "4"
                    },
                    "REDIS_PASSWORD": {
                      "isOptional": false,
                      "description": "Redis password",
                      "defaultValue": "${{Redis.REDISPASSWORD}}"
                    },
                    "MAP_STORAGE_URL": {
                      "isOptional": false,
                      "description": "gRPC address of the map storage service",
                      "defaultValue": "${{mapstorage.RAILWAY_PRIVATE_DOMAIN}}:50053"
                    },
                    "ENABLE_MAP_EDITOR": {
                      "description": "In-game map editor; keep off while there are no personal logins, or anyone could edit maps",
                      "defaultValue": "false"
                    },
                    "ENABLE_CHAT_UPLOAD": {
                      "isOptional": false,
                      "description": "Allows sending files in the chat",
                      "defaultValue": "true"
                    },
                    "PUBLIC_MAP_STORAGE_URL": {
                      "isOptional": false,
                      "description": "Map storage as seen by browsers",
                      "defaultValue": "https://${{proxy.RAILWAY_PUBLIC_DOMAIN}}/map-storage"
                    },
                    "INTERNAL_MAP_STORAGE_URL": {
                      "isOptional": false,
                      "description": "Map storage over the private network",
                      "defaultValue": "http://${{mapstorage.RAILWAY_PRIVATE_DOMAIN}}:3000"
                    },
                    "STORE_VARIABLES_FOR_LOCAL_MAPS": {
                      "isOptional": false,
                      "description": "Keeps map variables (e.g. door states) in Redis across restarts",
                      "defaultValue": "true"
                    }
                  }
                },
                "4e3a2af6-1039-41fa-ac9c-27e92c1b9bf0": {
                  "icon": "https://cdn.sanity.io/images/sy1jschh/production/0ce0bfdcfbdbf69662b1116671f97c2dd788b655-157x157.svg",
                  "name": "Redis",
                  "deploy": {
                    "startCommand": "/bin/sh -c \"rm -rf $RAILWAY_VOLUME_MOUNT_PATH/lost+found/ && exec docker-entrypoint.sh redis-server --requirepass $REDIS_PASSWORD --save 60 1 --dir $RAILWAY_VOLUME_MOUNT_PATH\"",
                    "healthcheckPath": null,
                    "restartPolicyType": "ON_FAILURE",
                    "restartPolicyMaxRetries": 10
                  },
                  "source": {
                    "image": "redis:8.2"
                  },
                  "variables": {
                    "REDISHOST": {
                      "isOptional": false,
                      "description": "Redis host on Railway's private network; other services reference this value",
                      "defaultValue": "${{RAILWAY_PRIVATE_DOMAIN}}"
                    },
                    "REDISPORT": {
                      "isOptional": false,
                      "description": "Port Redis listens on",
                      "defaultValue": "6379"
                    },
                    "REDISUSER": {
                      "isOptional": false,
                      "description": "Redis username; \"default\" is the built-in user that the password applies to",
                      "defaultValue": "default"
                    },
                    "REDIS_URL": {
                      "isOptional": false,
                      "description": "Full connection string over the private network",
                      "defaultValue": "redis://${{REDISUSER}}:${{REDIS_PASSWORD}}@${{REDISHOST}}:${{REDISPORT}}"
                    },
                    "REDISPASSWORD": {
                      "isOptional": false,
                      "description": "Password for connecting, mirrors REDIS_PASSWORD; referenced by play, back and uploader",
                      "defaultValue": "${{REDIS_PASSWORD}}"
                    },
                    "REDIS_PASSWORD": {
                      "isOptional": false,
                      "description": "Password Redis requires, 32 random letters generated per deploy",
                      "defaultValue": "{{REDIS_PASSWORD}}"
                    }
                  },
                  "volumeMounts": {
                    "4e3a2af6-1039-41fa-ac9c-27e92c1b9bf0": {
                      "mountPath": "/data"
                    }
                  }
                },
                "8bb323a0-9444-43de-aba8-42b40872f163": {
                  "icon": null,
                  "name": "icon",
                  "deploy": {
                    "startCommand": null,
                    "healthcheckPath": null,
                    "restartPolicyType": "ON_FAILURE",
                    "restartPolicyMaxRetries": 10
                  },
                  "source": {
                    "image": "matthiasluedtke/iconserver:v3.21.0"
                  },
                  "variables": {
                    "PORT": {
                      "isOptional": false,
                      "description": "Port the favicon service listens on; set explicitly because Railway may inject a different PORT",
                      "defaultValue": "8080"
                    }
                  }
                },
                "b5c8aa0c-7555-48e9-adaf-dbddc4cef0b6": {
                  "icon": null,
                  "name": "play",
                  "deploy": {
                    "startCommand": null,
                    "healthcheckPath": null,
                    "restartPolicyType": "ON_FAILURE",
                    "restartPolicyMaxRetries": 10
                  },
                  "source": {
                    "image": "thecodingmachine/workadventure-play:v1.34.4"
                  },
                  "variables": {
                    "API_URL": {
                      "isOptional": false,
                      "description": "gRPC address of the back service",
                      "defaultValue": "${{back.RAILWAY_PRIVATE_DOMAIN}}:50051"
                    },
                    "ICON_URL": {
                      "isOptional": false,
                      "description": "Path of the favicon service behind the proxy",
                      "defaultValue": "/icon"
                    },
                    "FRONT_URL": {
                      "isOptional": false,
                      "description": "Path of the game front end",
                      "defaultValue": "/"
                    },
                    "JITSI_URL": {
                      "isOptional": false,
                      "description": "Jitsi server for meeting room areas; must match the back service",
                      "defaultValue": "meet.jit.si"
                    },
                    "PUSHER_URL": {
                      "isOptional": false,
                      "description": "Public URL of the app, with trailing slash",
                      "defaultValue": "https://${{proxy.RAILWAY_PUBLIC_DOMAIN}}/"
                    },
                    "REDIS_HOST": {
                      "isOptional": false,
                      "description": "Redis host on the private network",
                      "defaultValue": "${{Redis.REDISHOST}}"
                    },
                    "REDIS_PORT": {
                      "isOptional": false,
                      "description": "Redis port",
                      "defaultValue": "${{Redis.REDISPORT}}"
                    },
                    "SECRET_KEY": {
                      "isOptional": false,
                      "description": "Same secret as the back service",
                      "defaultValue": "${{back.SECRET_KEY}}"
                    },
                    "ENABLE_CHAT": {
                      "isOptional": false,
                      "description": "Enables the proximity chat (messages are not stored)",
                      "defaultValue": "true"
                    },
                    "UPLOADER_URL": {
                      "isOptional": false,
                      "description": "Path of the chat upload service behind the proxy",
                      "defaultValue": "/uploader"
                    },
                    "MAX_PER_GROUP": {
                      "isOptional": false,
                      "description": "Maximum number of people in one proximity video bubble; must match the back service",
                      "defaultValue": "4"
                    },
                    "REDIS_PASSWORD": {
                      "isOptional": false,
                      "description": "Redis password",
                      "defaultValue": "${{Redis.REDISPASSWORD}}"
                    },
                    "START_ROOM_URL": {
                      "isOptional": false,
                      "description": "Map visitors land on; for an uploaded map use a path like /~/office.wam",
                      "defaultValue": "/_/global/workadventure.github.io/map-starter-kit/office.tmj"
                    },
                    "DISABLE_ANONYMOUS": {
                      "isOptional": false,
                      "description": "Keep false; true only works with an OpenID Connect provider configured",
                      "defaultValue": "false"
                    },
                    "ENABLE_MAP_EDITOR": {
                      "description": "In-game map editor; must match the back service",
                      "defaultValue": "false"
                    },
                    "ENABLE_CHAT_UPLOAD": {
                      "isOptional": false,
                      "description": "Allows sending files in the chat",
                      "defaultValue": "true"
                    },
                    "MAX_USERNAME_LENGTH": {
                      "isOptional": false,
                      "description": "Maximum length of player names",
                      "defaultValue": "10"
                    },
                    "MAP_STORAGE_API_TOKEN": {
                      "isOptional": false,
                      "description": "Token play and mapstorage use to call each other; same as the shared secret",
                      "defaultValue": "${{back.SECRET_KEY}}"
                    },
                    "PUBLIC_MAP_STORAGE_URL": {
                      "isOptional": false,
                      "description": "Map storage as seen by browsers",
                      "defaultValue": "https://${{proxy.RAILWAY_PUBLIC_DOMAIN}}/map-storage"
                    },
                    "INTERNAL_MAP_STORAGE_URL": {
                      "isOptional": false,
                      "description": "Map storage over the private network",
                      "defaultValue": "http://${{mapstorage.RAILWAY_PRIVATE_DOMAIN}}:3000"
                    }
                  }
                },
                "bc1bdeb6-a539-4069-b2e8-4bca4a33d2ea": {
                  "icon": null,
                  "name": "mapstorage",
                  "deploy": {
                    "startCommand": null,
                    "healthcheckPath": null,
                    "restartPolicyType": "ON_FAILURE",
                    "restartPolicyMaxRetries": 10
                  },
                  "source": {
                    "image": "thecodingmachine/workadventure-map-storage:v1.34.4"
                  },
                  "variables": {
                    "API_URL": {
                      "isOptional": false,
                      "description": "gRPC address of the back service",
                      "defaultValue": "${{back.RAILWAY_PRIVATE_DOMAIN}}:50051"
                    },
                    "PUSHER_URL": {
                      "isOptional": false,
                      "description": "Public URL of the app, with trailing slash",
                      "defaultValue": "https://${{proxy.RAILWAY_PUBLIC_DOMAIN}}/"
                    },
                    "SECRET_KEY": {
                      "isOptional": false,
                      "description": "Same secret as the back service",
                      "defaultValue": "${{back.SECRET_KEY}}"
                    },
                    "PATH_PREFIX": {
                      "isOptional": false,
                      "description": "Path the proxy serves map storage under",
                      "defaultValue": "/map-storage"
                    },
                    "AUTHENTICATION_USER": {
                      "isOptional": false,
                      "description": "Username for the map management page",
                      "defaultValue": "admin"
                    },
                    "AUTHENTICATION_TOKEN": {
                      "description": "API key to enter in the map-starter-kit upload settings",
                      "defaultValue": "{{AUTHENTICATION_TOKEN}}"
                    },
                    "MAP_STORAGE_API_TOKEN": {
                      "isOptional": false,
                      "description": "Token play and mapstorage use to call each other; same as the shared secret",
                      "defaultValue": "${{back.SECRET_KEY}}"
                    },
                    "ENTITY_COLLECTION_URLS": {
                      "isOptional": false,
                      "description": "Furniture catalogs offered in the map editor",
                      "defaultValue": "https://${{proxy.RAILWAY_PUBLIC_DOMAIN}}/collections/FurnitureCollection.json,https://${{proxy.RAILWAY_PUBLIC_DOMAIN}}/collections/OfficeCollection.json"
                    },
                    "AUTHENTICATION_PASSWORD": {
                      "isOptional": false,
                      "description": "Password for the map management page; separate from the site password",
                      "defaultValue": "{{AUTHENTICATION_PASSWORD}}"
                    },
                    "ENABLE_BASIC_AUTHENTICATION": {
                      "isOptional": false,
                      "description": "Protects the map management page at /map-storage/ with a username and password",
                      "defaultValue": "true"
                    },
                    "ENABLE_BEARER_AUTHENTICATION": {
                      "description": "Lets the map-starter-kit upload command authenticate with an API key",
                      "defaultValue": "true"
                    }
                  },
                  "volumeMounts": {
                    "bc1bdeb6-a539-4069-b2e8-4bca4a33d2ea": {
                      "mountPath": "/maps"
                    }
                  }
                },
                "e51124d3-1001-4603-94e1-71c29aa09454": {
                  "icon": null,
                  "name": "proxy",
                  "deploy": {
                    "startCommand": null,
                    "healthcheckPath": null,
                    "restartPolicyType": "ON_FAILURE",
                    "restartPolicyMaxRetries": 10
                  },
                  "source": {
                    "repo": "https://github.com/sukrutnrvd/workadventure-railway",
                    "rootDirectory": null
                  },
                  "variables": {
                    "PORT": {
                      "isOptional": false,
                      "description": "Port Caddy listens on; must match the public domain's target port",
                      "defaultValue": "8080"
                    },
                    "BACK_HOST": {
                      "isOptional": false,
                      "description": "Private hostname of the back service, served under /api",
                      "defaultValue": "${{back.RAILWAY_PRIVATE_DOMAIN}}"
                    },
                    "ICON_HOST": {
                      "isOptional": false,
                      "description": "Private hostname of the favicon service, served under /icon",
                      "defaultValue": "${{icon.RAILWAY_PRIVATE_DOMAIN}}"
                    },
                    "PLAY_HOST": {
                      "isOptional": false,
                      "description": "Private hostname of the play service (game front end and WebSockets)",
                      "defaultValue": "${{play.RAILWAY_PRIVATE_DOMAIN}}"
                    },
                    "ACCESS_USER": {
                      "isOptional": false,
                      "description": "Username everyone enters to open the site; letters, digits, '.', '_' and '-' only",
                      "defaultValue": "workadventure"
                    },
                    "UPLOADER_HOST": {
                      "isOptional": false,
                      "description": "Private hostname of the chat upload service, served under /uploader",
                      "defaultValue": "${{uploader.RAILWAY_PRIVATE_DOMAIN}}"
                    },
                    "ACCESS_PASSWORD": {
                      "isOptional": false,
                      "description": "Shared password for the site; changing it signs everyone out; leave empty to make the site public",
                      "defaultValue": "{{ACCESS_PASSWORD}}"
                    },
                    "MAP_STORAGE_HOST": {
                      "isOptional": false,
                      "description": "Private hostname of the map storage service, served under /map-storage",
                      "defaultValue": "${{mapstorage.RAILWAY_PRIVATE_DOMAIN}}"
                    },
                    "ACCESS_COOKIE_MAX_AGE": {
                      "description": "How long a login lasts in the same browser, in seconds (2592000 = 30 days)",
                      "defaultValue": "2592000"
                    }
                  },
                  "networking": {
                    "serviceDomains": {
                      "<hasDomain>:8080": {
                        "port": 8080
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  },
  "post_deploy": {},
  "resources": {
    "expected_services": 7,
    "needs_volume": true
  },
  "generated_at": "2026-10-25T04:14:45.632Z",
  "generator_version": "0.1.0"
}
