{
  "manifest_version": "1.0.0",
  "template": {
    "id": "a4296ee7-0754-4f87-b633-bd2e3ab73cb4",
    "slug": "posthog-product-analytics-suite",
    "name": "PostHog Product Analytics Suite",
    "description": "Self-hosted product analytics, session replay, feature flags and A/B tests.",
    "url": "https://railway.com/deploy/posthog-product-analytics-suite",
    "upstream": {
      "repo_url": "https://github.com/baranberkay96/posthog-railway"
    }
  },
  "services": [
    {
      "name": "temporal",
      "source": {
        "image": "temporalio/auto-setup:1.29.7"
      },
      "needs_volume": false,
      "http": false
    },
    {
      "name": "Postgres",
      "source": {
        "image": "ghcr.io/railwayapp-templates/postgres-ssl:18"
      },
      "needs_volume": true,
      "volume_mount_path": "/var/lib/postgresql/data",
      "http": false
    },
    {
      "name": "seaweedfs",
      "source": {
        "repo": "https://github.com/baranberkay96/posthog-railway"
      },
      "needs_volume": true,
      "volume_mount_path": "/data",
      "http": false
    },
    {
      "name": "proxy",
      "source": {
        "repo": "https://github.com/baranberkay96/posthog-railway"
      },
      "needs_volume": false,
      "http": true
    },
    {
      "name": "browserless",
      "source": {
        "image": "ghcr.io/browserless/chromium:v2.57.0"
      },
      "needs_volume": false,
      "http": false
    },
    {
      "name": "plugins",
      "source": {
        "repo": "https://github.com/baranberkay96/posthog-railway"
      },
      "needs_volume": false,
      "http": false
    },
    {
      "name": "kafka",
      "source": {
        "repo": "https://github.com/baranberkay96/posthog-railway"
      },
      "needs_volume": true,
      "volume_mount_path": "/var/lib/redpanda/data",
      "http": false
    },
    {
      "name": "zookeeper",
      "source": {
        "image": "zookeeper:3.9.6"
      },
      "needs_volume": true,
      "volume_mount_path": "/data",
      "http": false
    },
    {
      "name": "property-defs",
      "source": {
        "repo": "https://github.com/baranberkay96/posthog-railway"
      },
      "needs_volume": false,
      "http": false
    },
    {
      "name": "capture-logs",
      "source": {
        "image": "ghcr.io/posthog/posthog/capture-logs:sha-04cdf1c"
      },
      "needs_volume": false,
      "http": false
    },
    {
      "name": "hypercache-server",
      "source": {
        "image": "ghcr.io/posthog/posthog/hypercache-server:sha-14bcc04"
      },
      "needs_volume": false,
      "http": false
    },
    {
      "name": "Redis",
      "source": {
        "image": "redis:7.2.16-alpine"
      },
      "needs_volume": true,
      "volume_mount_path": "/data",
      "http": false
    },
    {
      "name": "capture",
      "source": {
        "repo": "https://github.com/baranberkay96/posthog-railway"
      },
      "needs_volume": false,
      "http": false
    },
    {
      "name": "temporal-django-worker",
      "source": {
        "image": "posthog/posthog:sha-716405ddea318758493221f26e844512757c7927"
      },
      "needs_volume": false,
      "http": false
    },
    {
      "name": "feature-flags",
      "source": {
        "repo": "https://github.com/baranberkay96/posthog-railway"
      },
      "needs_volume": false,
      "http": false
    },
    {
      "name": "worker",
      "source": {
        "image": "posthog/posthog:sha-716405ddea318758493221f26e844512757c7927"
      },
      "needs_volume": false,
      "http": false
    },
    {
      "name": "personhog",
      "source": {
        "repo": "https://github.com/baranberkay96/posthog-railway"
      },
      "needs_volume": false,
      "http": false
    },
    {
      "name": "recordings",
      "source": {
        "repo": "https://github.com/baranberkay96/posthog-railway"
      },
      "needs_volume": false,
      "http": false
    },
    {
      "name": "clickhouse",
      "source": {
        "repo": "https://github.com/baranberkay96/posthog-railway"
      },
      "needs_volume": true,
      "volume_mount_path": "/var/lib/clickhouse",
      "http": false
    },
    {
      "name": "livestream",
      "source": {
        "image": "ghcr.io/posthog/posthog/livestream:397fc8862e1ca5121a8679f0f686afde88d70b14"
      },
      "needs_volume": false,
      "http": false
    },
    {
      "name": "cymbal",
      "source": {
        "repo": "https://github.com/baranberkay96/posthog-railway"
      },
      "needs_volume": false,
      "http": false
    },
    {
      "name": "ingestion",
      "source": {
        "repo": "https://github.com/baranberkay96/posthog-railway"
      },
      "needs_volume": false,
      "http": false
    },
    {
      "name": "web",
      "source": {
        "image": "posthog/posthog:sha-716405ddea318758493221f26e844512757c7927"
      },
      "needs_volume": false,
      "http": false
    }
  ],
  "required_inputs": [
    {
      "key": "DB",
      "service": "temporal",
      "description": "Postgres persistence plugin.",
      "secret": false,
      "strategy": "default",
      "default": "postgres12"
    },
    {
      "key": "PORT",
      "service": "temporal",
      "description": "Frontend HTTP API port; /api/v1/system-info is the healthcheck.",
      "secret": false,
      "strategy": "default",
      "default": "7243"
    },
    {
      "key": "DB_PORT",
      "service": "temporal",
      "description": "Postgres port.",
      "secret": false,
      "strategy": "default",
      "default": "5432"
    },
    {
      "key": "ENABLE_ES",
      "service": "temporal",
      "description": "SQL visibility store (upstream hobby setting).",
      "secret": false,
      "strategy": "default",
      "default": "false"
    },
    {
      "key": "BIND_ON_IP",
      "service": "temporal",
      "description": "Listen on all interfaces (dual-stack).",
      "secret": false,
      "strategy": "default",
      "default": "::0"
    },
    {
      "key": "POSTGRES_PWD",
      "service": "temporal",
      "description": "Postgres password (reference).",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "POSTGRES_USER",
      "service": "temporal",
      "description": "Postgres user (needs CREATE DATABASE).",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "POSTGRES_SEEDS",
      "service": "temporal",
      "description": "Postgres host.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_private_domain"
    },
    {
      "key": "TEMPORAL_ADDRESS",
      "service": "temporal",
      "description": "Address the setup script uses to create the namespace.",
      "secret": false,
      "strategy": "default",
      "default": "127.0.0.1:7233"
    },
    {
      "key": "DYNAMIC_CONFIG_FILE_PATH",
      "service": "temporal",
      "description": "Dynamic config shipped in the image.",
      "secret": false,
      "strategy": "default",
      "default": "config/dynamicconfig/docker.yaml"
    },
    {
      "key": "TEMPORAL_BROADCAST_ADDRESS",
      "service": "temporal",
      "description": "Single-node membership address.",
      "secret": false,
      "strategy": "default",
      "default": "127.0.0.1"
    },
    {
      "key": "RAILWAY_DEPLOYMENT_DRAINING_SECONDS",
      "service": "temporal",
      "description": "Clean shutdown on redeploy.",
      "secret": false,
      "strategy": "default",
      "default": "30"
    },
    {
      "key": "PGDATA",
      "service": "Postgres",
      "description": "Location where the database will be initialized",
      "secret": false,
      "strategy": "default",
      "default": "/var/lib/postgresql/data/pgdata"
    },
    {
      "key": "PGHOST",
      "service": "Postgres",
      "description": "Railway Private Domain Name.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_private_domain"
    },
    {
      "key": "PGPORT",
      "service": "Postgres",
      "description": "Port to connect to Postgres.",
      "secret": false,
      "strategy": "default",
      "default": "5432"
    },
    {
      "key": "PGUSER",
      "service": "Postgres",
      "description": "Required variable for Data panel",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "PGDATABASE",
      "service": "Postgres",
      "description": "Required variable for the data panel.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "PGPASSWORD",
      "service": "Postgres",
      "description": "Required variable for Data panel",
      "secret": true,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "POSTGRES_DB",
      "service": "Postgres",
      "description": "Default database created when image is started (PostHog's database name).",
      "secret": false,
      "strategy": "default",
      "default": "posthog"
    },
    {
      "key": "DATABASE_URL",
      "service": "Postgres",
      "description": "URL to connect to Postgres database.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_private_domain"
    },
    {
      "key": "POSTGRES_USER",
      "service": "Postgres",
      "description": "User to connect to Postgres DB",
      "secret": false,
      "strategy": "default",
      "default": "postgres"
    },
    {
      "key": "SSL_CERT_DAYS",
      "service": "Postgres",
      "description": "SSL certificate expiry in days.",
      "secret": false,
      "strategy": "default",
      "default": "820"
    },
    {
      "key": "POSTGRES_PASSWORD",
      "service": "Postgres",
      "description": "Password to connect to DB",
      "secret": true,
      "strategy": "generate",
      "generate": "strong_password"
    },
    {
      "key": "RAILWAY_DEPLOYMENT_DRAINING_SECONDS",
      "service": "Postgres",
      "description": "Allow Postgres to cleanly shut down",
      "secret": false,
      "strategy": "default",
      "default": "60"
    },
    {
      "key": "PORT",
      "service": "seaweedfs",
      "description": "S3 port; /healthz is the healthcheck.",
      "secret": false,
      "strategy": "default",
      "default": "8333"
    },
    {
      "key": "S3_PORT",
      "service": "seaweedfs",
      "description": "S3 gateway port.",
      "secret": false,
      "strategy": "default",
      "default": "8333"
    },
    {
      "key": "S3_BUCKETS",
      "service": "seaweedfs",
      "description": "Buckets created at start (idempotent).",
      "secret": false,
      "strategy": "default",
      "default": "posthog,ai-blobs"
    },
    {
      "key": "AWS_ACCESS_KEY_ID",
      "service": "seaweedfs",
      "description": "S3 access key (admin identity).",
      "secret": true,
      "strategy": "generate",
      "generate": "random_base64_32"
    },
    {
      "key": "AWS_SECRET_ACCESS_KEY",
      "service": "seaweedfs",
      "description": "S3 secret key.",
      "secret": true,
      "strategy": "generate",
      "generate": "random_base64_32"
    },
    {
      "key": "RAILWAY_DEPLOYMENT_DRAINING_SECONDS",
      "service": "seaweedfs",
      "description": "Clean shutdown on redeploy.",
      "secret": false,
      "strategy": "default",
      "default": "30"
    },
    {
      "key": "PORT",
      "service": "proxy",
      "description": "Caddy listen port (public domain target).",
      "secret": false,
      "strategy": "default",
      "default": "8080"
    },
    {
      "key": "WEB_UPSTREAM",
      "service": "proxy",
      "description": "Django web app.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_private_domain"
    },
    {
      "key": "CAPTURE_UPSTREAM",
      "service": "proxy",
      "description": "Event capture (/e, /i/v0, /batch, /capture).",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_private_domain"
    },
    {
      "key": "PLUGINS_UPSTREAM",
      "service": "proxy",
      "description": "Webhook sources (/public/webhooks, /public/m).",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_private_domain"
    },
    {
      "key": "CAPTURE_AI_UPSTREAM",
      "service": "proxy",
      "description": "LLM analytics capture (/i/v0/ai; ai process of the capture service).",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_private_domain"
    },
    {
      "key": "HYPERCACHE_UPSTREAM",
      "service": "proxy",
      "description": "Surveys and remote config (/surveys, /array).",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_private_domain"
    },
    {
      "key": "LIVESTREAM_UPSTREAM",
      "service": "proxy",
      "description": "Live events stream (/livestream).",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_private_domain"
    },
    {
      "key": "CAPTURE_LOGS_UPSTREAM",
      "service": "proxy",
      "description": "OTLP logs/traces/metrics capture (/i/v1/logs, /i/v1/traces, /i/v1/metrics).",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_private_domain"
    },
    {
      "key": "FEATURE_FLAGS_UPSTREAM",
      "service": "proxy",
      "description": "Feature flags (/flags, local evaluation).",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_private_domain"
    },
    {
      "key": "OBJECTSTORAGE_UPSTREAM",
      "service": "proxy",
      "description": "Presigned object downloads (/posthog/*).",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_private_domain"
    },
    {
      "key": "REPLAY_CAPTURE_UPSTREAM",
      "service": "proxy",
      "description": "Session replay capture (/s; recordings process of the capture service).",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_private_domain"
    },
    {
      "key": "HOST",
      "service": "browserless",
      "description": "Listen on all interfaces (dual-stack).",
      "secret": false,
      "strategy": "default",
      "default": "::"
    },
    {
      "key": "PORT",
      "service": "browserless",
      "description": "HTTP/WebSocket port.",
      "secret": false,
      "strategy": "default",
      "default": "3000"
    },
    {
      "key": "DEBUG",
      "service": "browserless",
      "description": "Silence debug namespaces (upstream hobby value).",
      "secret": false,
      "strategy": "default",
      "default": "-*"
    },
    {
      "key": "TOKEN",
      "service": "browserless",
      "description": "Browserless API token (separate from Django's SECRET_KEY).",
      "secret": true,
      "strategy": "generate",
      "generate": "random_base64_32"
    },
    {
      "key": "LOG_LEVEL",
      "service": "browserless",
      "description": "Log level (upstream hobby value).",
      "secret": false,
      "strategy": "default",
      "default": "warn"
    },
    {
      "key": "PORT",
      "service": "plugins",
      "description": "Node HTTP server port (HTTP_SERVER_PORT default); /_health is the healthcheck.",
      "secret": false,
      "strategy": "default",
      "default": "6738"
    },
    {
      "key": "SITE_URL",
      "service": "plugins",
      "description": "Public URL of PostHog.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "REDIS_URL",
      "service": "plugins",
      "description": "Redis connection string.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "SECRET_KEY",
      "service": "plugins",
      "description": "Must match web.",
      "secret": true,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "KAFKA_HOSTS",
      "service": "plugins",
      "description": "Kafka (Redpanda) bootstrap server.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_private_domain"
    },
    {
      "key": "DATABASE_URL",
      "service": "plugins",
      "description": "Postgres connection string.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "CDP_REDIS_HOST",
      "service": "plugins",
      "description": "Redis host for CDP state (function health, rate limits).",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "CDP_REDIS_PORT",
      "service": "plugins",
      "description": "Redis port.",
      "secret": false,
      "strategy": "default",
      "default": "6379"
    },
    {
      "key": "LOGS_REDIS_TLS",
      "service": "plugins",
      "description": "No TLS on the private network.",
      "secret": false,
      "strategy": "default",
      "default": "false"
    },
    {
      "key": "CDP_VALKEY_HOST",
      "service": "plugins",
      "description": "Not read by the pinned node build. Newer builds dual-write CDP state to a Valkey host and refuse to start without one; it points at Redis so an upgrade keeps working (the hobby compose runs a separate Valkey).",
      "secret": true,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "CDP_VALKEY_PORT",
      "service": "plugins",
      "description": "Port for CDP_VALKEY_HOST.",
      "secret": true,
      "strategy": "default",
      "default": "6379"
    },
    {
      "key": "CLICKHOUSE_HOST",
      "service": "plugins",
      "description": "ClickHouse host.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_private_domain"
    },
    {
      "key": "CLICKHOUSE_USER",
      "service": "plugins",
      "description": "ClickHouse user.",
      "secret": false,
      "strategy": "default",
      "default": "default"
    },
    {
      "key": "LOGS_REDIS_HOST",
      "service": "plugins",
      "description": "Redis for logs-product state. The pinned node build does not pass LOGS_REDIS_PASSWORD to this pool, so the full URL (with password) goes here; ioredis accepts it.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "LOGS_REDIS_PORT",
      "service": "plugins",
      "description": "Redis port.",
      "secret": false,
      "strategy": "default",
      "default": "6379"
    },
    {
      "key": "TRACES_REDIS_TLS",
      "service": "plugins",
      "description": "No TLS on the private network.",
      "secret": false,
      "strategy": "default",
      "default": "false"
    },
    {
      "key": "CLICKHOUSE_SECURE",
      "service": "plugins",
      "description": "Plain TCP inside the private network.",
      "secret": false,
      "strategy": "default",
      "default": "false"
    },
    {
      "key": "CLICKHOUSE_VERIFY",
      "service": "plugins",
      "description": "No TLS verification.",
      "secret": false,
      "strategy": "default",
      "default": "false"
    },
    {
      "key": "TRACES_REDIS_HOST",
      "service": "plugins",
      "description": "Redis for traces-product state. Full URL with password, as for LOGS_REDIS_HOST.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "TRACES_REDIS_PORT",
      "service": "plugins",
      "description": "Redis port.",
      "secret": false,
      "strategy": "default",
      "default": "6379"
    },
    {
      "key": "CDP_REDIS_PASSWORD",
      "service": "plugins",
      "description": "Redis password (reference).",
      "secret": true,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "CDP_VALKEY_PASSWORD",
      "service": "plugins",
      "description": "Password for CDP_VALKEY_HOST (reference).",
      "secret": true,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "CLICKHOUSE_DATABASE",
      "service": "plugins",
      "description": "ClickHouse database.",
      "secret": false,
      "strategy": "default",
      "default": "posthog"
    },
    {
      "key": "CLICKHOUSE_PASSWORD",
      "service": "plugins",
      "description": "ClickHouse password (reference).",
      "secret": true,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "LOGS_REDIS_PASSWORD",
      "service": "plugins",
      "description": "Redis password (reference).",
      "secret": true,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "ENCRYPTION_SALT_KEYS",
      "service": "plugins",
      "description": "Must match web (decrypts encrypted function inputs).",
      "secret": true,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "PERSONS_DATABASE_URL",
      "service": "plugins",
      "description": "Persons live in the main database (hobby layout).",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "TRACES_REDIS_PASSWORD",
      "service": "plugins",
      "description": "Redis password (reference).",
      "secret": true,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "OBJECT_STORAGE_ENABLED",
      "service": "plugins",
      "description": "Use object storage.",
      "secret": false,
      "strategy": "default",
      "default": "true"
    },
    {
      "key": "OBJECT_STORAGE_ENDPOINT",
      "service": "plugins",
      "description": "SeaweedFS S3 endpoint.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_private_domain"
    },
    {
      "key": "NODEJS_CAPABILITY_GROUPS",
      "service": "plugins",
      "description": "Capabilities of this process: the default plugin-server set plus traces ingestion (replaces upstream's ingestion-logs and ingestion-traces services).",
      "secret": false,
      "strategy": "default",
      "default": "cdp_workflows,realtime_cohorts,logs,traces,feature_flags"
    },
    {
      "key": "OBJECT_STORAGE_ACCESS_KEY_ID",
      "service": "plugins",
      "description": "Object storage access key (reference).",
      "secret": true,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "OBJECT_STORAGE_PUBLIC_ENDPOINT",
      "service": "plugins",
      "description": "Public base URL for presigned links.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "BEHAVIORAL_COHORTS_DATABASE_URL",
      "service": "plugins",
      "description": "Behavioral cohorts live in the main database (hobby layout).",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "OBJECT_STORAGE_SECRET_ACCESS_KEY",
      "service": "plugins",
      "description": "Object storage secret key (reference).",
      "secret": true,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "PORT",
      "service": "kafka",
      "description": "Admin API port; /v1/status/ready is the healthcheck.",
      "secret": false,
      "strategy": "default",
      "default": "9644"
    },
    {
      "key": "REDPANDA_SMP",
      "service": "kafka",
      "description": "CPU cores Redpanda uses.",
      "secret": false,
      "strategy": "default",
      "default": "1"
    },
    {
      "key": "REDPANDA_MEMORY",
      "service": "kafka",
      "description": "Memory Redpanda allocates (upstream hobby uses 3G).",
      "secret": false,
      "strategy": "default",
      "default": "1G"
    },
    {
      "key": "KAFKA_LOG_RETENTION_MS",
      "service": "kafka",
      "description": "Topic retention (24 h). Kafka is a buffer here; ClickHouse holds the data.",
      "secret": false,
      "strategy": "default",
      "default": "86400000"
    },
    {
      "key": "RAILWAY_DEPLOYMENT_DRAINING_SECONDS",
      "service": "kafka",
      "description": "Clean shutdown on redeploy.",
      "secret": false,
      "strategy": "default",
      "default": "30"
    },
    {
      "key": "PORT",
      "service": "zookeeper",
      "description": "ZooKeeper AdminServer port; /commands/ruok is the healthcheck.",
      "secret": false,
      "strategy": "default",
      "default": "8080"
    },
    {
      "key": "ZK_SERVER_HEAP",
      "service": "zookeeper",
      "description": "JVM heap in MB (image default 1000); ClickHouse's coordination data is small.",
      "secret": false,
      "strategy": "default",
      "default": "256"
    },
    {
      "key": "ZOO_DATA_LOG_DIR",
      "service": "zookeeper",
      "description": "Transaction log on the volume (Railway allows one volume per service).",
      "secret": false,
      "strategy": "default",
      "default": "/data/datalog"
    },
    {
      "key": "ZOO_AUTOPURGE_PURGEINTERVAL",
      "service": "zookeeper",
      "description": "Purge old snapshots hourly (upstream hobby value).",
      "secret": false,
      "strategy": "default",
      "default": "1"
    },
    {
      "key": "ZOO_AUTOPURGE_SNAPRETAINCOUNT",
      "service": "zookeeper",
      "description": "Snapshots to keep (upstream hobby value).",
      "secret": false,
      "strategy": "default",
      "default": "3"
    },
    {
      "key": "RAILWAY_DEPLOYMENT_DRAINING_SECONDS",
      "service": "zookeeper",
      "description": "Clean shutdown on redeploy.",
      "secret": false,
      "strategy": "default",
      "default": "15"
    },
    {
      "key": "PORT",
      "service": "property-defs",
      "description": "HTTP port of the events process (/_readiness).",
      "secret": false,
      "strategy": "default",
      "default": "3301"
    },
    {
      "key": "SKIP_READS",
      "service": "property-defs",
      "description": "Read existing definitions.",
      "secret": false,
      "strategy": "default",
      "default": "false"
    },
    {
      "key": "FILTER_MODE",
      "service": "property-defs",
      "description": "Process all teams unless opted out.",
      "secret": false,
      "strategy": "default",
      "default": "opt-out"
    },
    {
      "key": "KAFKA_HOSTS",
      "service": "property-defs",
      "description": "Kafka bootstrap server.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_private_domain"
    },
    {
      "key": "SKIP_WRITES",
      "service": "property-defs",
      "description": "Write definitions.",
      "secret": false,
      "strategy": "default",
      "default": "false"
    },
    {
      "key": "DATABASE_URL",
      "service": "property-defs",
      "description": "Postgres connection string.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "PORT",
      "service": "capture-logs",
      "description": "Management port (/_readiness, /_liveness, metrics); Railway healthcheck target.",
      "secret": false,
      "strategy": "default",
      "default": "8080"
    },
    {
      "key": "RUST_LOG",
      "service": "capture-logs",
      "description": "Log level.",
      "secret": false,
      "strategy": "default",
      "default": "info,rdkafka=warn"
    },
    {
      "key": "BIND_HOST",
      "service": "capture-logs",
      "description": "OTLP listen address (dual-stack).",
      "secret": false,
      "strategy": "default",
      "default": "::"
    },
    {
      "key": "BIND_PORT",
      "service": "capture-logs",
      "description": "OTLP HTTP port.",
      "secret": false,
      "strategy": "default",
      "default": "4318"
    },
    {
      "key": "JWT_SECRET",
      "service": "capture-logs",
      "description": "Secret for capture-logs JWT handling (upstream compose ships a placeholder string).",
      "secret": true,
      "strategy": "generate",
      "generate": "random_base64_32"
    },
    {
      "key": "KAFKA_HOSTS",
      "service": "capture-logs",
      "description": "Kafka bootstrap server.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_private_domain"
    },
    {
      "key": "KAFKA_TOPIC",
      "service": "capture-logs",
      "description": "Logs topic.",
      "secret": false,
      "strategy": "default",
      "default": "logs_ingestion"
    },
    {
      "key": "RUST_BACKTRACE",
      "service": "capture-logs",
      "description": "Backtraces on panic.",
      "secret": false,
      "strategy": "default",
      "default": "1"
    },
    {
      "key": "KAFKA_METRICS_TOPIC",
      "service": "capture-logs",
      "description": "Metrics topic.",
      "secret": false,
      "strategy": "default",
      "default": "metrics_ingestion"
    },
    {
      "key": "MANAGEMENT_BIND_PORT",
      "service": "capture-logs",
      "description": "Management port.",
      "secret": false,
      "strategy": "default",
      "default": "8080"
    },
    {
      "key": "RAILWAY_DEPLOYMENT_DRAINING_SECONDS",
      "service": "capture-logs",
      "description": "Short drain on redeploy.",
      "secret": false,
      "strategy": "default",
      "default": "15"
    },
    {
      "key": "PORT",
      "service": "hypercache-server",
      "description": "HTTP port; /_readiness is the healthcheck.",
      "secret": false,
      "strategy": "default",
      "default": "3002"
    },
    {
      "key": "ADDRESS",
      "service": "hypercache-server",
      "description": "Bind address (dual-stack).",
      "secret": false,
      "strategy": "default",
      "default": "[::]:3002"
    },
    {
      "key": "RUST_LOG",
      "service": "hypercache-server",
      "description": "Log level.",
      "secret": false,
      "strategy": "default",
      "default": "info"
    },
    {
      "key": "REDIS_URL",
      "service": "hypercache-server",
      "description": "Redis connection string.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "AWS_ACCESS_KEY_ID",
      "service": "hypercache-server",
      "description": "Object storage access key (reference).",
      "secret": true,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "AWS_SECRET_ACCESS_KEY",
      "service": "hypercache-server",
      "description": "Object storage secret key (reference).",
      "secret": true,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "OBJECT_STORAGE_ENDPOINT",
      "service": "hypercache-server",
      "description": "HyperCache S3 tier endpoint (SeaweedFS).",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_private_domain"
    },
    {
      "key": "RAILWAY_DEPLOYMENT_DRAINING_SECONDS",
      "service": "hypercache-server",
      "description": "Short drain on redeploy.",
      "secret": false,
      "strategy": "default",
      "default": "15"
    },
    {
      "key": "REDISHOST",
      "service": "Redis",
      "description": "Private network hostname of the Redis service, only resolvable from services in the same environment",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_private_domain"
    },
    {
      "key": "REDISPORT",
      "service": "Redis",
      "description": "Port that Redis listens on",
      "secret": false,
      "strategy": "default",
      "default": "6379"
    },
    {
      "key": "REDISUSER",
      "service": "Redis",
      "description": "Username for authenticating with Redis",
      "secret": false,
      "strategy": "default",
      "default": "default"
    },
    {
      "key": "REDIS_URL",
      "service": "Redis",
      "description": "Connection string for connecting to Redis using the private network",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "REDISPASSWORD",
      "service": "Redis",
      "description": "Alias of REDIS_PASSWORD for clients that expect the unseparated name",
      "secret": true,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "REDIS_PASSWORD",
      "service": "Redis",
      "description": "Randomly generated password for authenticating with Redis",
      "secret": true,
      "strategy": "generate",
      "generate": "strong_password"
    },
    {
      "key": "REDIS_MAXMEMORY",
      "service": "Redis",
      "description": "Memory cap with LRU eviction (hobby compose uses 200mb).",
      "secret": false,
      "strategy": "default",
      "default": "512mb"
    },
    {
      "key": "PORT",
      "service": "capture",
      "description": "Events capture port; /_readiness is the healthcheck.",
      "secret": false,
      "strategy": "default",
      "default": "3000"
    },
    {
      "key": "RUST_LOG",
      "service": "capture",
      "description": "Log level.",
      "secret": false,
      "strategy": "default",
      "default": "info,rdkafka=warn"
    },
    {
      "key": "REDIS_URL",
      "service": "capture",
      "description": "Redis (quota limits, event restrictions).",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "KAFKA_HOSTS",
      "service": "capture",
      "description": "Kafka bootstrap server.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_private_domain"
    },
    {
      "key": "CAPTURE_AI_PORT",
      "service": "capture",
      "description": "Port of the LLM analytics (ai) process.",
      "secret": false,
      "strategy": "default",
      "default": "3001"
    },
    {
      "key": "CAPTURE_EVENTS_PORT",
      "service": "capture",
      "description": "Port of the events process.",
      "secret": false,
      "strategy": "default",
      "default": "3000"
    },
    {
      "key": "CAPTURE_REPLAY_PORT",
      "service": "capture",
      "description": "Port of the session replay (recordings) process.",
      "secret": false,
      "strategy": "default",
      "default": "3002"
    },
    {
      "key": "CAPTURE_AI_LANE_TOPIC",
      "service": "capture",
      "description": "Topic for LLM analytics events. The main topic, because the pinned Node build does not consume PostHog's separate AI lane (events_plugin_ingestion_ai); change only together with a Node image that does.",
      "secret": false,
      "strategy": "default",
      "default": "events_plugin_ingestion"
    },
    {
      "key": "RAILWAY_DEPLOYMENT_DRAINING_SECONDS",
      "service": "capture",
      "description": "Short drain on redeploy.",
      "secret": false,
      "strategy": "default",
      "default": "15"
    },
    {
      "key": "KAFKA_INGESTION_PRODUCER_METADATA_BROKER_LIST",
      "service": "capture",
      "description": "Kafka metadata broker list for the producer.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_private_domain"
    },
    {
      "key": "SITE_URL",
      "service": "temporal-django-worker",
      "description": "Same as web: Public URL of PostHog (the proxy domain).",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "REDIS_URL",
      "service": "temporal-django-worker",
      "description": "Same as web: Redis for cache, Celery broker and locks.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "DEPLOYMENT",
      "service": "temporal-django-worker",
      "description": "Same as web: Deployment type; hobby keeps persons in the main database.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "SECRET_KEY",
      "service": "temporal-django-worker",
      "description": "Same as web: Django secret key; signs sessions and tokens.",
      "secret": true,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "CDP_API_URL",
      "service": "temporal-django-worker",
      "description": "Same as web: Internal URL of the plugins (CDP) service.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "KAFKA_HOSTS",
      "service": "temporal-django-worker",
      "description": "Same as web: Kafka (Redpanda) bootstrap server.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "DATABASE_URL",
      "service": "temporal-django-worker",
      "description": "Same as web: Postgres connection string.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "OPENAI_MODEL",
      "service": "temporal-django-worker",
      "description": "Same as web: Model used for OpenAI-backed assists.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "TEMPORAL_HOST",
      "service": "temporal-django-worker",
      "description": "Same as web: Temporal frontend host (batch exports, data warehouse, workflows).",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "OPENAI_API_KEY",
      "service": "temporal-django-worker",
      "description": "Same as web: Optional OpenAI key for SQL/regex assist.",
      "secret": true,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "PERSONHOG_ADDR",
      "service": "temporal-django-worker",
      "description": "Same as web: gRPC address of the personhog router.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "CLICKHOUSE_HOST",
      "service": "temporal-django-worker",
      "description": "Same as web: ClickHouse host (private network).",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "CLICKHOUSE_USER",
      "service": "temporal-django-worker",
      "description": "Same as web: ClickHouse admin user used for queries and migrations.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "IS_BEHIND_PROXY",
      "service": "temporal-django-worker",
      "description": "Same as web: Trust X-Forwarded-* from the Caddy proxy / Railway edge.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "OPENAI_BASE_URL",
      "service": "temporal-django-worker",
      "description": "Same as web: OpenAI-compatible API base URL.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "ANTHROPIC_API_KEY",
      "service": "temporal-django-worker",
      "description": "Same as web: Optional Anthropic key for PostHog AI.",
      "secret": true,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "BROWSERLESS_TOKEN",
      "service": "temporal-django-worker",
      "description": "Browserless token (reference).",
      "secret": true,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "CLICKHOUSE_SECURE",
      "service": "temporal-django-worker",
      "description": "Same as web: Plain TCP inside the private network.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "CLICKHOUSE_VERIFY",
      "service": "temporal-django-worker",
      "description": "Same as web: No TLS verification (no TLS on the private network).",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "OTEL_SDK_DISABLED",
      "service": "temporal-django-worker",
      "description": "Same as web: No OpenTelemetry export from Django.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "PERSONHOG_ENABLED",
      "service": "temporal-django-worker",
      "description": "Same as web: Read persons through personhog, as upstream hobby does.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "RECORDING_API_URL",
      "service": "temporal-django-worker",
      "description": "Same as web: Internal URL of the recording API (replay playback).",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "BROWSERLESS_CDP_URL",
      "service": "temporal-django-worker",
      "description": "Browserless CDP endpoint for image exports.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_private_domain"
    },
    {
      "key": "CLICKHOUSE_API_USER",
      "service": "temporal-django-worker",
      "description": "Same as web: ClickHouse user for API queries.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "CLICKHOUSE_APP_USER",
      "service": "temporal-django-worker",
      "description": "Same as web: ClickHouse user for app queries.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "CLICKHOUSE_DATABASE",
      "service": "temporal-django-worker",
      "description": "Same as web: ClickHouse database PostHog uses.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "CLICKHOUSE_PASSWORD",
      "service": "temporal-django-worker",
      "description": "Same as web: ClickHouse default-user password.",
      "secret": true,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "INTERNAL_API_SECRET",
      "service": "temporal-django-worker",
      "description": "Same as web: Shared secret for internal service-to-service calls.",
      "secret": true,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "API_QUERIES_PER_TEAM",
      "service": "temporal-django-worker",
      "description": "Same as web: Concurrent API query limit per team (upstream hobby value).",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "ENCRYPTION_SALT_KEYS",
      "service": "temporal-django-worker",
      "description": "Same as web: Salt for encrypted fields (integration secrets).",
      "secret": true,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "PERSONS_DB_READER_URL",
      "service": "temporal-django-worker",
      "description": "Same as web: Persons database reader (same Postgres database).",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "PERSONS_DB_WRITER_URL",
      "service": "temporal-django-worker",
      "description": "Same as web: Persons database (same Postgres database in this stack).",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "INTERNAL_REQUEST_TOKEN",
      "service": "temporal-django-worker",
      "description": "Same as web: Token for Django to feature-flags calls.",
      "secret": true,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "OBJECT_STORAGE_ENABLED",
      "service": "temporal-django-worker",
      "description": "Same as web: Use S3 object storage for exports and media.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "CLICKHOUSE_API_PASSWORD",
      "service": "temporal-django-worker",
      "description": "Same as web: Password of the api user.",
      "secret": true,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "CLICKHOUSE_APP_PASSWORD",
      "service": "temporal-django-worker",
      "description": "Same as web: Password of the app user.",
      "secret": true,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "HEATMAP_BROWSERLESS_URL",
      "service": "temporal-django-worker",
      "description": "Browserless HTTP endpoint for heatmap screenshots.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_private_domain"
    },
    {
      "key": "OBJECT_STORAGE_ENDPOINT",
      "service": "temporal-django-worker",
      "description": "Same as web: SeaweedFS S3 endpoint for exports, media and AI blobs.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "FEATURE_FLAGS_SERVICE_URL",
      "service": "temporal-django-worker",
      "description": "Same as web: Internal URL of the Rust feature-flags service.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "HEATMAP_BROWSERLESS_TOKEN",
      "service": "temporal-django-worker",
      "description": "Browserless token (reference).",
      "secret": true,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "CLICKHOUSE_DICT_READER_USER",
      "service": "temporal-django-worker",
      "description": "Same as web: Read-only user ClickHouse dictionaries authenticate as.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "DISABLE_SECURE_SSL_REDIRECT",
      "service": "temporal-django-worker",
      "description": "Same as web: TLS is terminated by Railway; no redirect loop.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "CLICKHOUSE_LOGS_CLUSTER_HOST",
      "service": "temporal-django-worker",
      "description": "Same as web: ClickHouse host for the logs product (same server).",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "OBJECT_STORAGE_ACCESS_KEY_ID",
      "service": "temporal-django-worker",
      "description": "Same as web: Object storage access key.",
      "secret": true,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "CLICKHOUSE_LOGS_CLUSTER_SECURE",
      "service": "temporal-django-worker",
      "description": "Same as web: Plain TCP for the logs cluster connection.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "OBJECT_STORAGE_PUBLIC_ENDPOINT",
      "service": "temporal-django-worker",
      "description": "Same as web: Base URL for presigned downloads (proxied under /posthog).",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "CLICKHOUSE_DICT_READER_PASSWORD",
      "service": "temporal-django-worker",
      "description": "Same as web: Password of the dict_reader user.",
      "secret": true,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "OBJECT_STORAGE_FORCE_PATH_STYLE",
      "service": "temporal-django-worker",
      "description": "Same as web: SeaweedFS needs path-style requests.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "CLICKHOUSE_LOGS_CLUSTER_PASSWORD",
      "service": "temporal-django-worker",
      "description": "Same as web: Password for the logs cluster connection (default user).",
      "secret": true,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "OBJECT_STORAGE_SECRET_ACCESS_KEY",
      "service": "temporal-django-worker",
      "description": "Same as web: Object storage secret key.",
      "secret": true,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "SESSION_RECORDING_V2_S3_ENDPOINT",
      "service": "temporal-django-worker",
      "description": "Same as web: SeaweedFS S3 endpoint for session recordings.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "RAILWAY_DEPLOYMENT_DRAINING_SECONDS",
      "service": "temporal-django-worker",
      "description": "Let running activities finish on redeploy.",
      "secret": false,
      "strategy": "default",
      "default": "60"
    },
    {
      "key": "SESSION_RECORDING_V2_S3_ACCESS_KEY_ID",
      "service": "temporal-django-worker",
      "description": "Same as web: Recording store access key.",
      "secret": true,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "SESSION_RECORDING_V2_S3_SECRET_ACCESS_KEY",
      "service": "temporal-django-worker",
      "description": "Same as web: Recording store secret key.",
      "secret": true,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "HEATMAP_BROWSERLESS_SCREENSHOT_COOKIES_ENABLED",
      "service": "temporal-django-worker",
      "description": "Do not forward cookies to heatmap screenshots (upstream default).",
      "secret": false,
      "strategy": "default",
      "default": "false"
    },
    {
      "key": "PORT",
      "service": "feature-flags",
      "description": "HTTP port; /_readiness is the healthcheck.",
      "secret": false,
      "strategy": "default",
      "default": "3001"
    },
    {
      "key": "ADDRESS",
      "service": "feature-flags",
      "description": "Bind address (dual-stack).",
      "secret": false,
      "strategy": "default",
      "default": "[::]:3001"
    },
    {
      "key": "RUST_LOG",
      "service": "feature-flags",
      "description": "Log level.",
      "secret": false,
      "strategy": "default",
      "default": "info"
    },
    {
      "key": "REDIS_URL",
      "service": "feature-flags",
      "description": "Redis for team and flag caches.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "AWS_ACCESS_KEY_ID",
      "service": "feature-flags",
      "description": "Object storage access key (reference).",
      "secret": true,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "READ_DATABASE_URL",
      "service": "feature-flags",
      "description": "Postgres (reader).",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "WRITE_DATABASE_URL",
      "service": "feature-flags",
      "description": "Postgres (writer).",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "AWS_SECRET_ACCESS_KEY",
      "service": "feature-flags",
      "description": "Object storage secret key (reference).",
      "secret": true,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "COOKIELESS_REDIS_HOST",
      "service": "feature-flags",
      "description": "Cookieless-mode Redis. The service builds redis://HOST:PORT from this value, so the credentials are embedded in the host part.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "COOKIELESS_REDIS_PORT",
      "service": "feature-flags",
      "description": "Redis port.",
      "secret": false,
      "strategy": "default",
      "default": "6379"
    },
    {
      "key": "INTERNAL_REQUEST_TOKEN",
      "service": "feature-flags",
      "description": "Must match web (flag test evaluation).",
      "secret": true,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "OBJECT_STORAGE_ENDPOINT",
      "service": "feature-flags",
      "description": "HyperCache S3 tier endpoint (SeaweedFS).",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_private_domain"
    },
    {
      "key": "PERSONS_READ_DATABASE_URL",
      "service": "feature-flags",
      "description": "Persons database reader.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "PERSONS_WRITE_DATABASE_URL",
      "service": "feature-flags",
      "description": "Persons database (main database in the hobby layout).",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "RAILWAY_DEPLOYMENT_DRAINING_SECONDS",
      "service": "feature-flags",
      "description": "Short drain on redeploy.",
      "secret": false,
      "strategy": "default",
      "default": "15"
    },
    {
      "key": "SITE_URL",
      "service": "worker",
      "description": "Same as web: Public URL of PostHog (the proxy domain).",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "REDIS_URL",
      "service": "worker",
      "description": "Same as web: Redis for cache, Celery broker and locks.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "DEPLOYMENT",
      "service": "worker",
      "description": "Same as web: Deployment type; hobby keeps persons in the main database.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "SECRET_KEY",
      "service": "worker",
      "description": "Same as web: Django secret key; signs sessions and tokens.",
      "secret": true,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "CDP_API_URL",
      "service": "worker",
      "description": "Same as web: Internal URL of the plugins (CDP) service.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "KAFKA_HOSTS",
      "service": "worker",
      "description": "Same as web: Kafka (Redpanda) bootstrap server.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "DATABASE_URL",
      "service": "worker",
      "description": "Same as web: Postgres connection string.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "OPENAI_MODEL",
      "service": "worker",
      "description": "Same as web: Model used for OpenAI-backed assists.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "TEMPORAL_HOST",
      "service": "worker",
      "description": "Same as web: Temporal frontend host (batch exports, data warehouse, workflows).",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "OPENAI_API_KEY",
      "service": "worker",
      "description": "Same as web: Optional OpenAI key for SQL/regex assist.",
      "secret": true,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "PERSONHOG_ADDR",
      "service": "worker",
      "description": "Same as web: gRPC address of the personhog router.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "CLICKHOUSE_HOST",
      "service": "worker",
      "description": "Same as web: ClickHouse host (private network).",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "CLICKHOUSE_USER",
      "service": "worker",
      "description": "Same as web: ClickHouse admin user used for queries and migrations.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "IS_BEHIND_PROXY",
      "service": "worker",
      "description": "Same as web: Trust X-Forwarded-* from the Caddy proxy / Railway edge.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "OPENAI_BASE_URL",
      "service": "worker",
      "description": "Same as web: OpenAI-compatible API base URL.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "WEB_CONCURRENCY",
      "service": "worker",
      "description": "Celery worker processes. Upstream default is one per CPU, which on Railway means the host's CPU count.",
      "secret": false,
      "strategy": "default",
      "default": "2"
    },
    {
      "key": "ANTHROPIC_API_KEY",
      "service": "worker",
      "description": "Same as web: Optional Anthropic key for PostHog AI.",
      "secret": true,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "BROWSERLESS_TOKEN",
      "service": "worker",
      "description": "Browserless token (reference).",
      "secret": true,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "CLICKHOUSE_SECURE",
      "service": "worker",
      "description": "Same as web: Plain TCP inside the private network.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "CLICKHOUSE_VERIFY",
      "service": "worker",
      "description": "Same as web: No TLS verification (no TLS on the private network).",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "OTEL_SDK_DISABLED",
      "service": "worker",
      "description": "Same as web: No OpenTelemetry export from Django.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "PERSONHOG_ENABLED",
      "service": "worker",
      "description": "Same as web: Read persons through personhog, as upstream hobby does.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "RECORDING_API_URL",
      "service": "worker",
      "description": "Same as web: Internal URL of the recording API (replay playback).",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "BROWSERLESS_CDP_URL",
      "service": "worker",
      "description": "Browserless CDP endpoint for image exports.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_private_domain"
    },
    {
      "key": "CLICKHOUSE_API_USER",
      "service": "worker",
      "description": "Same as web: ClickHouse user for API queries.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "CLICKHOUSE_APP_USER",
      "service": "worker",
      "description": "Same as web: ClickHouse user for app queries.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "CLICKHOUSE_DATABASE",
      "service": "worker",
      "description": "Same as web: ClickHouse database PostHog uses.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "CLICKHOUSE_PASSWORD",
      "service": "worker",
      "description": "Same as web: ClickHouse default-user password.",
      "secret": true,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "INTERNAL_API_SECRET",
      "service": "worker",
      "description": "Same as web: Shared secret for internal service-to-service calls.",
      "secret": true,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "API_QUERIES_PER_TEAM",
      "service": "worker",
      "description": "Same as web: Concurrent API query limit per team (upstream hobby value).",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "ENCRYPTION_SALT_KEYS",
      "service": "worker",
      "description": "Same as web: Salt for encrypted fields (integration secrets).",
      "secret": true,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "PERSONS_DB_READER_URL",
      "service": "worker",
      "description": "Same as web: Persons database reader (same Postgres database).",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "PERSONS_DB_WRITER_URL",
      "service": "worker",
      "description": "Same as web: Persons database (same Postgres database in this stack).",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "INTERNAL_REQUEST_TOKEN",
      "service": "worker",
      "description": "Same as web: Token for Django to feature-flags calls.",
      "secret": true,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "OBJECT_STORAGE_ENABLED",
      "service": "worker",
      "description": "Same as web: Use S3 object storage for exports and media.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "CLICKHOUSE_API_PASSWORD",
      "service": "worker",
      "description": "Same as web: Password of the api user.",
      "secret": true,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "CLICKHOUSE_APP_PASSWORD",
      "service": "worker",
      "description": "Same as web: Password of the app user.",
      "secret": true,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "HEATMAP_BROWSERLESS_URL",
      "service": "worker",
      "description": "Browserless HTTP endpoint for heatmap screenshots.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_private_domain"
    },
    {
      "key": "OBJECT_STORAGE_ENDPOINT",
      "service": "worker",
      "description": "Same as web: SeaweedFS S3 endpoint for exports, media and AI blobs.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "FEATURE_FLAGS_SERVICE_URL",
      "service": "worker",
      "description": "Same as web: Internal URL of the Rust feature-flags service.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "HEATMAP_BROWSERLESS_TOKEN",
      "service": "worker",
      "description": "Browserless token (reference).",
      "secret": true,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "CLICKHOUSE_DICT_READER_USER",
      "service": "worker",
      "description": "Same as web: Read-only user ClickHouse dictionaries authenticate as.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "DISABLE_SECURE_SSL_REDIRECT",
      "service": "worker",
      "description": "Same as web: TLS is terminated by Railway; no redirect loop.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "CLICKHOUSE_LOGS_CLUSTER_HOST",
      "service": "worker",
      "description": "Same as web: ClickHouse host for the logs product (same server).",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "OBJECT_STORAGE_ACCESS_KEY_ID",
      "service": "worker",
      "description": "Same as web: Object storage access key.",
      "secret": true,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "POSTHOG_SKIP_MIGRATION_CHECKS",
      "service": "worker",
      "description": "Migrations run in web's pre-deploy step; do not block on them here (upstream hobby setting).",
      "secret": false,
      "strategy": "default",
      "default": "1"
    },
    {
      "key": "CLICKHOUSE_LOGS_CLUSTER_SECURE",
      "service": "worker",
      "description": "Same as web: Plain TCP for the logs cluster connection.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "OBJECT_STORAGE_PUBLIC_ENDPOINT",
      "service": "worker",
      "description": "Same as web: Base URL for presigned downloads (proxied under /posthog).",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "CLICKHOUSE_DICT_READER_PASSWORD",
      "service": "worker",
      "description": "Same as web: Password of the dict_reader user.",
      "secret": true,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "OBJECT_STORAGE_FORCE_PATH_STYLE",
      "service": "worker",
      "description": "Same as web: SeaweedFS needs path-style requests.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "CLICKHOUSE_LOGS_CLUSTER_PASSWORD",
      "service": "worker",
      "description": "Same as web: Password for the logs cluster connection (default user).",
      "secret": true,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "OBJECT_STORAGE_SECRET_ACCESS_KEY",
      "service": "worker",
      "description": "Same as web: Object storage secret key.",
      "secret": true,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "SESSION_RECORDING_V2_S3_ENDPOINT",
      "service": "worker",
      "description": "Same as web: SeaweedFS S3 endpoint for session recordings.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "RAILWAY_DEPLOYMENT_DRAINING_SECONDS",
      "service": "worker",
      "description": "Let running Celery tasks finish on redeploy.",
      "secret": false,
      "strategy": "default",
      "default": "60"
    },
    {
      "key": "SESSION_RECORDING_V2_S3_ACCESS_KEY_ID",
      "service": "worker",
      "description": "Same as web: Recording store access key.",
      "secret": true,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "SESSION_RECORDING_V2_S3_SECRET_ACCESS_KEY",
      "service": "worker",
      "description": "Same as web: Recording store secret key.",
      "secret": true,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "HEATMAP_BROWSERLESS_SCREENSHOT_COOKIES_ENABLED",
      "service": "worker",
      "description": "Do not forward cookies to heatmap screenshots (upstream default).",
      "secret": false,
      "strategy": "default",
      "default": "false"
    },
    {
      "key": "PORT",
      "service": "personhog",
      "description": "Router metrics/health port; /_readiness is the healthcheck.",
      "secret": false,
      "strategy": "default",
      "default": "9101"
    },
    {
      "key": "RUST_LOG",
      "service": "personhog",
      "description": "Log level.",
      "secret": false,
      "strategy": "default",
      "default": "info"
    },
    {
      "key": "BACKEND_TIMEOUT_MS",
      "service": "personhog",
      "description": "Router-to-replica call timeout.",
      "secret": false,
      "strategy": "default",
      "default": "5000"
    },
    {
      "key": "PRIMARY_DATABASE_URL",
      "service": "personhog",
      "description": "Persons database (main database in the hobby layout).",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "PORT",
      "service": "recordings",
      "description": "Node HTTP server port (HTTP_SERVER_PORT default); /_health is the healthcheck.",
      "secret": false,
      "strategy": "default",
      "default": "6738"
    },
    {
      "key": "REDIS_URL",
      "service": "recordings",
      "description": "Redis connection string.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "KAFKA_HOSTS",
      "service": "recordings",
      "description": "Kafka (Redpanda) bootstrap server.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_private_domain"
    },
    {
      "key": "DATABASE_URL",
      "service": "recordings",
      "description": "Postgres connection string.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "NODE_PROCESSES",
      "service": "recordings",
      "description": "Node processes in this service (mode:port). web calls the recording API on 6739.",
      "secret": false,
      "strategy": "default",
      "default": "recordings-blob-ingestion-v2:6738 recording-api:6739"
    },
    {
      "key": "CLICKHOUSE_HOST",
      "service": "recordings",
      "description": "ClickHouse host.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_private_domain"
    },
    {
      "key": "CLICKHOUSE_USER",
      "service": "recordings",
      "description": "ClickHouse user.",
      "secret": false,
      "strategy": "default",
      "default": "default"
    },
    {
      "key": "CLICKHOUSE_SECURE",
      "service": "recordings",
      "description": "Plain TCP inside the private network.",
      "secret": false,
      "strategy": "default",
      "default": "false"
    },
    {
      "key": "CLICKHOUSE_VERIFY",
      "service": "recordings",
      "description": "No TLS verification.",
      "secret": false,
      "strategy": "default",
      "default": "false"
    },
    {
      "key": "CLICKHOUSE_DATABASE",
      "service": "recordings",
      "description": "ClickHouse database.",
      "secret": false,
      "strategy": "default",
      "default": "posthog"
    },
    {
      "key": "CLICKHOUSE_PASSWORD",
      "service": "recordings",
      "description": "ClickHouse password (reference).",
      "secret": true,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "INTERNAL_API_SECRET",
      "service": "recordings",
      "description": "Must match web (X-Internal-Api-Secret on recording API calls).",
      "secret": true,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "ENCRYPTION_SALT_KEYS",
      "service": "recordings",
      "description": "Must match web (decrypts encrypted function inputs).",
      "secret": true,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "SESSION_RECORDING_API_REDIS_HOST",
      "service": "recordings",
      "description": "Redis for the recording API. This setting has no password field; ioredis accepts the full URL (with password) here.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "SESSION_RECORDING_API_REDIS_PORT",
      "service": "recordings",
      "description": "Redis port.",
      "secret": false,
      "strategy": "default",
      "default": "6379"
    },
    {
      "key": "SESSION_RECORDING_V2_S3_ENDPOINT",
      "service": "recordings",
      "description": "SeaweedFS S3 endpoint for recordings.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_private_domain"
    },
    {
      "key": "SESSION_RECORDING_V2_S3_TIMEOUT_MS",
      "service": "recordings",
      "description": "S3 request timeout (upstream hobby value).",
      "secret": false,
      "strategy": "default",
      "default": "120000"
    },
    {
      "key": "SESSION_RECORDING_V2_S3_ACCESS_KEY_ID",
      "service": "recordings",
      "description": "Recording store access key (reference).",
      "secret": true,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "SESSION_RECORDING_V2_S3_SECRET_ACCESS_KEY",
      "service": "recordings",
      "description": "Recording store secret key (reference).",
      "secret": true,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "PORT",
      "service": "clickhouse",
      "description": "HTTP port; /ping is the healthcheck.",
      "secret": false,
      "strategy": "default",
      "default": "8123"
    },
    {
      "key": "KAFKA_HOSTS",
      "service": "clickhouse",
      "description": "Brokers for PostHog's Kafka engine tables (named collections).",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_private_domain"
    },
    {
      "key": "ZOOKEEPER_HOST",
      "service": "clickhouse",
      "description": "ZooKeeper host for ON CLUSTER DDL and replicated tables.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_private_domain"
    },
    {
      "key": "CLICKHOUSE_PASSWORD",
      "service": "clickhouse",
      "description": "Password of the default (admin) user. Alphanumeric: PostHog embeds it in SQL.",
      "secret": true,
      "strategy": "generate",
      "generate": "strong_password"
    },
    {
      "key": "CLICKHOUSE_API_PASSWORD",
      "service": "clickhouse",
      "description": "Password of the api user.",
      "secret": true,
      "strategy": "generate",
      "generate": "strong_password"
    },
    {
      "key": "CLICKHOUSE_APP_PASSWORD",
      "service": "clickhouse",
      "description": "Password of the app user.",
      "secret": true,
      "strategy": "generate",
      "generate": "strong_password"
    },
    {
      "key": "CLICKHOUSE_DICT_READER_PASSWORD",
      "service": "clickhouse",
      "description": "Password of the read-only dict_reader user.",
      "secret": true,
      "strategy": "generate",
      "generate": "strong_password"
    },
    {
      "key": "RAILWAY_DEPLOYMENT_DRAINING_SECONDS",
      "service": "clickhouse",
      "description": "Let ClickHouse flush and stop cleanly.",
      "secret": false,
      "strategy": "default",
      "default": "60"
    },
    {
      "key": "PORT",
      "service": "livestream",
      "description": "HTTP port.",
      "secret": false,
      "strategy": "default",
      "default": "8080"
    },
    {
      "key": "LIVESTREAM_MMDB_PATH",
      "service": "livestream",
      "description": "GeoLite2 database shipped in the image.",
      "secret": false,
      "strategy": "default",
      "default": "/GeoLite2-City.mmdb"
    },
    {
      "key": "LIVESTREAM_JWT_SECRET",
      "service": "livestream",
      "description": "Must equal web's SECRET_KEY (signs live-events tokens).",
      "secret": true,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "LIVESTREAM_CONSUMERS_EVENT_TOPIC",
      "service": "livestream",
      "description": "Events topic.",
      "secret": false,
      "strategy": "default",
      "default": "events_plugin_ingestion"
    },
    {
      "key": "LIVESTREAM_CONSUMERS_EVENT_BROKERS",
      "service": "livestream",
      "description": "Kafka bootstrap server (events).",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_private_domain"
    },
    {
      "key": "LIVESTREAM_CONSUMERS_EVENT_GROUP_ID",
      "service": "livestream",
      "description": "Consumer group.",
      "secret": false,
      "strategy": "default",
      "default": "livestream"
    },
    {
      "key": "LIVESTREAM_CONSUMERS_EVENT_SECURITY_PROTOCOL",
      "service": "livestream",
      "description": "Kafka protocol.",
      "secret": false,
      "strategy": "default",
      "default": "PLAINTEXT"
    },
    {
      "key": "LIVESTREAM_CONSUMERS_SESSION_RECORDING_TOPIC",
      "service": "livestream",
      "description": "Recording snapshots topic.",
      "secret": false,
      "strategy": "default",
      "default": "session_recording_snapshot_item_events"
    },
    {
      "key": "LIVESTREAM_CONSUMERS_SESSION_RECORDING_BROKERS",
      "service": "livestream",
      "description": "Kafka bootstrap server (recordings).",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_private_domain"
    },
    {
      "key": "LIVESTREAM_CONSUMERS_SESSION_RECORDING_GROUP_ID",
      "service": "livestream",
      "description": "Consumer group.",
      "secret": false,
      "strategy": "default",
      "default": "livestream-session-recordings"
    },
    {
      "key": "LIVESTREAM_CONSUMERS_SESSION_RECORDING_SECURITY_PROTOCOL",
      "service": "livestream",
      "description": "Kafka protocol.",
      "secret": false,
      "strategy": "default",
      "default": "PLAINTEXT"
    },
    {
      "key": "PORT",
      "service": "cymbal",
      "description": "HTTP port of the processing process; /_readiness is the healthcheck.",
      "secret": false,
      "strategy": "default",
      "default": "3302"
    },
    {
      "key": "RUST_LOG",
      "service": "cymbal",
      "description": "Log level.",
      "secret": false,
      "strategy": "default",
      "default": "info"
    },
    {
      "key": "BIND_HOST",
      "service": "cymbal",
      "description": "Bind address (dual-stack).",
      "secret": false,
      "strategy": "default",
      "default": "::"
    },
    {
      "key": "BIND_PORT",
      "service": "cymbal",
      "description": "HTTP port.",
      "secret": false,
      "strategy": "default",
      "default": "3302"
    },
    {
      "key": "REDIS_URL",
      "service": "cymbal",
      "description": "Redis connection string.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "KAFKA_HOSTS",
      "service": "cymbal",
      "description": "Kafka bootstrap server.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_private_domain"
    },
    {
      "key": "PERSONS_URL",
      "service": "cymbal",
      "description": "Persons database (main database).",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "DATABASE_URL",
      "service": "cymbal",
      "description": "Postgres connection string.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "INTERNAL_API_SECRET",
      "service": "cymbal",
      "description": "Must match web.",
      "secret": true,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "OBJECT_STORAGE_BUCKET",
      "service": "cymbal",
      "description": "Bucket for symbol sets.",
      "secret": false,
      "strategy": "default",
      "default": "posthog"
    },
    {
      "key": "ISSUE_BUCKETS_REDIS_URL",
      "service": "cymbal",
      "description": "Redis for issue rate buckets.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "OBJECT_STORAGE_ENDPOINT",
      "service": "cymbal",
      "description": "SeaweedFS S3 endpoint.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_private_domain"
    },
    {
      "key": "OBJECT_STORAGE_ACCESS_KEY_ID",
      "service": "cymbal",
      "description": "Access key (reference).",
      "secret": true,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "OBJECT_STORAGE_FORCE_PATH_STYLE",
      "service": "cymbal",
      "description": "SeaweedFS needs path-style requests.",
      "secret": false,
      "strategy": "default",
      "default": "true"
    },
    {
      "key": "OBJECT_STORAGE_SECRET_ACCESS_KEY",
      "service": "cymbal",
      "description": "Secret key (reference).",
      "secret": true,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "PORT",
      "service": "ingestion",
      "description": "Node HTTP server port (HTTP_SERVER_PORT default); /_health is the healthcheck.",
      "secret": false,
      "strategy": "default",
      "default": "6738"
    },
    {
      "key": "REDIS_URL",
      "service": "ingestion",
      "description": "Redis connection string.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "KAFKA_HOSTS",
      "service": "ingestion",
      "description": "Kafka (Redpanda) bootstrap server.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_private_domain"
    },
    {
      "key": "DATABASE_URL",
      "service": "ingestion",
      "description": "Postgres connection string.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "CDP_REDIS_HOST",
      "service": "ingestion",
      "description": "Redis host for CDP state (function health, rate limits).",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "CDP_REDIS_PORT",
      "service": "ingestion",
      "description": "Redis port.",
      "secret": false,
      "strategy": "default",
      "default": "6379"
    },
    {
      "key": "NODE_PROCESSES",
      "service": "ingestion",
      "description": "Node processes in this service (mode:port). A process that exits restarts the service.",
      "secret": false,
      "strategy": "default",
      "default": "ingestion-v2-combined:6738 ingestion-errortracking:6739"
    },
    {
      "key": "PERSONHOG_ADDR",
      "service": "ingestion",
      "description": "personhog router (gRPC).",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_private_domain"
    },
    {
      "key": "CLICKHOUSE_HOST",
      "service": "ingestion",
      "description": "ClickHouse host.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_private_domain"
    },
    {
      "key": "CLICKHOUSE_USER",
      "service": "ingestion",
      "description": "ClickHouse user.",
      "secret": false,
      "strategy": "default",
      "default": "default"
    },
    {
      "key": "AI_BLOB_S3_BUCKET",
      "service": "ingestion",
      "description": "Bucket for offloaded multimodal AI payloads.",
      "secret": false,
      "strategy": "default",
      "default": "ai-blobs"
    },
    {
      "key": "AI_BLOB_S3_PREFIX",
      "service": "ingestion",
      "description": "Key prefix for AI blobs.",
      "secret": false,
      "strategy": "default",
      "default": "aio/"
    },
    {
      "key": "AI_BLOB_S3_REGION",
      "service": "ingestion",
      "description": "Region string for the S3 client.",
      "secret": false,
      "strategy": "default",
      "default": "us-east-1"
    },
    {
      "key": "CLICKHOUSE_SECURE",
      "service": "ingestion",
      "description": "Plain TCP inside the private network.",
      "secret": false,
      "strategy": "default",
      "default": "false"
    },
    {
      "key": "CLICKHOUSE_VERIFY",
      "service": "ingestion",
      "description": "No TLS verification.",
      "secret": false,
      "strategy": "default",
      "default": "false"
    },
    {
      "key": "PERSONHOG_ENABLED",
      "service": "ingestion",
      "description": "Read persons through personhog for the AI consumer.",
      "secret": false,
      "strategy": "default",
      "default": "true"
    },
    {
      "key": "CDP_REDIS_PASSWORD",
      "service": "ingestion",
      "description": "Redis password (reference).",
      "secret": true,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "AI_BLOB_S3_ENDPOINT",
      "service": "ingestion",
      "description": "SeaweedFS S3 endpoint.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_private_domain"
    },
    {
      "key": "CLICKHOUSE_DATABASE",
      "service": "ingestion",
      "description": "ClickHouse database.",
      "secret": false,
      "strategy": "default",
      "default": "posthog"
    },
    {
      "key": "CLICKHOUSE_PASSWORD",
      "service": "ingestion",
      "description": "ClickHouse password (reference).",
      "secret": true,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "ENCRYPTION_SALT_KEYS",
      "service": "ingestion",
      "description": "Must match web (decrypts encrypted function inputs).",
      "secret": true,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "PERSONS_DATABASE_URL",
      "service": "ingestion",
      "description": "Persons live in the main database (hobby layout).",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "AI_BLOB_OFFLOAD_TEAMS",
      "service": "ingestion",
      "description": "Offload AI blobs for all teams.",
      "secret": false,
      "strategy": "default",
      "default": "*"
    },
    {
      "key": "AI_BLOB_S3_ACCESS_KEY_ID",
      "service": "ingestion",
      "description": "Object storage access key (reference).",
      "secret": true,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "AI_BLOB_S3_SECRET_ACCESS_KEY",
      "service": "ingestion",
      "description": "Object storage secret key (reference).",
      "secret": true,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "ERROR_TRACKING_CYMBAL_BASE_URL",
      "service": "ingestion",
      "description": "cymbal processing service (error tracking process).",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_private_domain"
    },
    {
      "key": "BEHAVIORAL_COHORTS_DATABASE_URL",
      "service": "ingestion",
      "description": "Behavioral cohorts live in the main database (hobby layout).",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "INGESTION_AI_EVENT_SPLITTING_TEAMS",
      "service": "ingestion",
      "description": "Teams to split AI events for (all).",
      "secret": false,
      "strategy": "default",
      "default": "*"
    },
    {
      "key": "INGESTION_AI_EVENT_SPLITTING_ENABLED",
      "service": "ingestion",
      "description": "Write the full LLM analytics events (prompts, outputs) to the ai_events table and keep them out of the events table, as PostHog's AI lane does.",
      "secret": false,
      "strategy": "default",
      "default": "true"
    },
    {
      "key": "PORT",
      "service": "web",
      "description": "Granian HTTP port; Railway healthcheck probes it.",
      "secret": false,
      "strategy": "default",
      "default": "8000"
    },
    {
      "key": "SITE_URL",
      "service": "web",
      "description": "Public URL of PostHog (the proxy domain). Change it when you add a custom domain to the proxy.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_domain"
    },
    {
      "key": "REDIS_URL",
      "service": "web",
      "description": "Redis for cache, Celery broker and locks.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "DEPLOYMENT",
      "service": "web",
      "description": "Deployment type; hobby keeps persons in the main database and runs persons migrations.",
      "secret": false,
      "strategy": "default",
      "default": "hobby"
    },
    {
      "key": "SECRET_KEY",
      "service": "web",
      "description": "Django secret key (hobby installer format). Generated once; changing it logs everyone out.",
      "secret": true,
      "strategy": "generate",
      "generate": "random_base64_32"
    },
    {
      "key": "CDP_API_URL",
      "service": "web",
      "description": "Internal URL of the plugins (CDP) service.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_private_domain"
    },
    {
      "key": "KAFKA_HOSTS",
      "service": "web",
      "description": "Kafka (Redpanda) bootstrap server.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_private_domain"
    },
    {
      "key": "DATABASE_URL",
      "service": "web",
      "description": "Postgres connection string (private network).",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "OPENAI_MODEL",
      "service": "web",
      "description": "Model used for OpenAI-backed assists (upstream default).",
      "secret": false,
      "strategy": "default",
      "default": "gpt-4.1-mini"
    },
    {
      "key": "TEMPORAL_HOST",
      "service": "web",
      "description": "Temporal frontend host (batch exports, data warehouse, workflows).",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_private_domain"
    },
    {
      "key": "PERSONHOG_ADDR",
      "service": "web",
      "description": "gRPC address of the personhog router.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_private_domain"
    },
    {
      "key": "CLICKHOUSE_HOST",
      "service": "web",
      "description": "ClickHouse host (private network).",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_private_domain"
    },
    {
      "key": "CLICKHOUSE_USER",
      "service": "web",
      "description": "ClickHouse admin user used for queries and migrations.",
      "secret": false,
      "strategy": "default",
      "default": "default"
    },
    {
      "key": "GRANIAN_WORKERS",
      "service": "web",
      "description": "Web worker processes (~1.1 GB RAM each). Upstream default is 4; raise it for more concurrent API/UI requests.",
      "secret": false,
      "strategy": "default",
      "default": "2"
    },
    {
      "key": "IS_BEHIND_PROXY",
      "service": "web",
      "description": "Trust X-Forwarded-* from the Caddy proxy / Railway edge.",
      "secret": false,
      "strategy": "default",
      "default": "true"
    },
    {
      "key": "LIVESTREAM_HOST",
      "service": "web",
      "description": "Public URL of the live events stream (proxied to livestream).",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "OPENAI_BASE_URL",
      "service": "web",
      "description": "OpenAI-compatible API base URL.",
      "secret": false,
      "strategy": "default",
      "default": "https://api.openai.com/v1"
    },
    {
      "key": "OPT_OUT_CAPTURE",
      "service": "web",
      "description": "Anonymous usage reporting to PostHog Inc. (upstream default). Set true to opt out.",
      "secret": false,
      "strategy": "default",
      "default": "false"
    },
    {
      "key": "MIGRATE_WAIT_FOR",
      "service": "web",
      "description": "host:port list the pre-deploy step waits for before running migrations.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_private_domain"
    },
    {
      "key": "CLICKHOUSE_SECURE",
      "service": "web",
      "description": "Plain TCP inside the private network.",
      "secret": false,
      "strategy": "default",
      "default": "false"
    },
    {
      "key": "CLICKHOUSE_VERIFY",
      "service": "web",
      "description": "No TLS verification (no TLS on the private network).",
      "secret": false,
      "strategy": "default",
      "default": "false"
    },
    {
      "key": "OTEL_SDK_DISABLED",
      "service": "web",
      "description": "No OpenTelemetry export from Django.",
      "secret": false,
      "strategy": "default",
      "default": "true"
    },
    {
      "key": "OTEL_SERVICE_NAME",
      "service": "web",
      "description": "Service name if OpenTelemetry is enabled later.",
      "secret": false,
      "strategy": "default",
      "default": "posthog"
    },
    {
      "key": "PERSONHOG_ENABLED",
      "service": "web",
      "description": "Read persons through personhog, as the upstream hobby stack does.",
      "secret": false,
      "strategy": "default",
      "default": "true"
    },
    {
      "key": "RECORDING_API_URL",
      "service": "web",
      "description": "Internal URL of the recording API (replay playback; second process of the recordings service).",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_private_domain"
    },
    {
      "key": "CLICKHOUSE_API_USER",
      "service": "web",
      "description": "ClickHouse user for API queries.",
      "secret": false,
      "strategy": "default",
      "default": "api"
    },
    {
      "key": "CLICKHOUSE_APP_USER",
      "service": "web",
      "description": "ClickHouse user for app queries.",
      "secret": false,
      "strategy": "default",
      "default": "app"
    },
    {
      "key": "CLICKHOUSE_DATABASE",
      "service": "web",
      "description": "ClickHouse database PostHog uses.",
      "secret": false,
      "strategy": "default",
      "default": "posthog"
    },
    {
      "key": "CLICKHOUSE_PASSWORD",
      "service": "web",
      "description": "ClickHouse default-user password (reference).",
      "secret": true,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "INTERNAL_API_SECRET",
      "service": "web",
      "description": "Shared secret for internal calls (web/worker to recording-api, cymbal).",
      "secret": true,
      "strategy": "generate",
      "generate": "random_base64_32"
    },
    {
      "key": "API_QUERIES_PER_TEAM",
      "service": "web",
      "description": "Concurrent API query limit per team (upstream hobby value).",
      "secret": false,
      "strategy": "default",
      "default": "{\"1\": 100}"
    },
    {
      "key": "ENCRYPTION_SALT_KEYS",
      "service": "web",
      "description": "Salt for encrypted fields. Generated once; never change after first deploy.",
      "secret": true,
      "strategy": "generate",
      "generate": "random_base64_32"
    },
    {
      "key": "PERSONS_DB_READER_URL",
      "service": "web",
      "description": "Persons database reader (same Postgres database).",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "PERSONS_DB_WRITER_URL",
      "service": "web",
      "description": "Persons database (same Postgres database in the hobby layout).",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "INTERNAL_REQUEST_TOKEN",
      "service": "web",
      "description": "Token for Django to feature-flags calls (flag test evaluation).",
      "secret": true,
      "strategy": "generate",
      "generate": "random_base64_32"
    },
    {
      "key": "OBJECT_STORAGE_ENABLED",
      "service": "web",
      "description": "Use S3 object storage for exports and media.",
      "secret": false,
      "strategy": "default",
      "default": "true"
    },
    {
      "key": "CLICKHOUSE_API_PASSWORD",
      "service": "web",
      "description": "Password of the api user (reference).",
      "secret": true,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "CLICKHOUSE_APP_PASSWORD",
      "service": "web",
      "description": "Password of the app user (reference).",
      "secret": true,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "OBJECT_STORAGE_ENDPOINT",
      "service": "web",
      "description": "SeaweedFS S3 endpoint for exports, media and AI blobs (private network).",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_private_domain"
    },
    {
      "key": "FEATURE_FLAGS_SERVICE_URL",
      "service": "web",
      "description": "Internal URL of the Rust feature-flags service.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_private_domain"
    },
    {
      "key": "CLICKHOUSE_DICT_READER_USER",
      "service": "web",
      "description": "Read-only user ClickHouse dictionaries authenticate as.",
      "secret": false,
      "strategy": "default",
      "default": "dict_reader"
    },
    {
      "key": "DISABLE_SECURE_SSL_REDIRECT",
      "service": "web",
      "description": "TLS is terminated by Railway; avoids a redirect loop.",
      "secret": false,
      "strategy": "default",
      "default": "true"
    },
    {
      "key": "CLICKHOUSE_LOGS_CLUSTER_HOST",
      "service": "web",
      "description": "ClickHouse host for the logs product (same server; upstream default is localhost).",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_private_domain"
    },
    {
      "key": "OBJECT_STORAGE_ACCESS_KEY_ID",
      "service": "web",
      "description": "Object storage access key (reference).",
      "secret": true,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "CLICKHOUSE_LOGS_CLUSTER_SECURE",
      "service": "web",
      "description": "Plain TCP for the logs cluster connection.",
      "secret": false,
      "strategy": "default",
      "default": "false"
    },
    {
      "key": "OBJECT_STORAGE_PUBLIC_ENDPOINT",
      "service": "web",
      "description": "Base URL for presigned downloads; the proxy forwards /posthog/* to seaweedfs.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "CLICKHOUSE_DICT_READER_PASSWORD",
      "service": "web",
      "description": "Password of the dict_reader user (reference).",
      "secret": true,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "OBJECT_STORAGE_FORCE_PATH_STYLE",
      "service": "web",
      "description": "SeaweedFS needs path-style requests.",
      "secret": false,
      "strategy": "default",
      "default": "true"
    },
    {
      "key": "CLICKHOUSE_LOGS_CLUSTER_PASSWORD",
      "service": "web",
      "description": "Password for the logs cluster connection (default user).",
      "secret": true,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "OBJECT_STORAGE_SECRET_ACCESS_KEY",
      "service": "web",
      "description": "Object storage secret key (reference).",
      "secret": true,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "SESSION_RECORDING_V2_S3_ENDPOINT",
      "service": "web",
      "description": "SeaweedFS S3 endpoint for session recordings.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_private_domain"
    },
    {
      "key": "RAILWAY_DEPLOYMENT_DRAINING_SECONDS",
      "service": "web",
      "description": "Let in-flight requests finish on redeploy.",
      "secret": false,
      "strategy": "default",
      "default": "30"
    },
    {
      "key": "SESSION_RECORDING_V2_S3_ACCESS_KEY_ID",
      "service": "web",
      "description": "Recording store access key (reference).",
      "secret": true,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "SESSION_RECORDING_V2_S3_SECRET_ACCESS_KEY",
      "service": "web",
      "description": "Recording store secret key (reference).",
      "secret": true,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    }
  ],
  "deploy": {
    "mcp": {
      "server": "railway",
      "tool": "deploy_template",
      "args": {
        "template_code": "posthog-product-analytics-suite"
      }
    },
    "cli": "railway deploy --template posthog-product-analytics-suite",
    "api": {
      "method": "POST",
      "path": "/graphql/v2",
      "body": {
        "query": "mutation templateDeploy($input: TemplateDeployV2Input!) { templateDeployV2(input: $input) { projectId workflowId } }",
        "variables": {
          "input": {
            "templateId": "a4296ee7-0754-4f87-b633-bd2e3ab73cb4",
            "serializedConfig": {
              "buckets": {},
              "services": {
                "00dd7db3-94b8-56f6-b56e-a7cd626845d7": {
                  "icon": "https://temporal.io/favicon.svg",
                  "name": "temporal",
                  "deploy": {
                    "healthcheckPath": "/api/v1/system-info",
                    "restartPolicyType": "ALWAYS",
                    "healthcheckTimeout": 1200
                  },
                  "source": {
                    "image": "temporalio/auto-setup:1.29.7"
                  },
                  "variables": {
                    "DB": {
                      "isOptional": true,
                      "description": "Postgres persistence plugin.",
                      "defaultValue": "postgres12"
                    },
                    "PORT": {
                      "isOptional": true,
                      "description": "Frontend HTTP API port; /api/v1/system-info is the healthcheck.",
                      "defaultValue": "7243"
                    },
                    "DB_PORT": {
                      "isOptional": true,
                      "description": "Postgres port.",
                      "defaultValue": "5432"
                    },
                    "ENABLE_ES": {
                      "isOptional": true,
                      "description": "SQL visibility store (upstream hobby setting).",
                      "defaultValue": "false"
                    },
                    "BIND_ON_IP": {
                      "isOptional": true,
                      "description": "Listen on all interfaces (dual-stack).",
                      "defaultValue": "::0"
                    },
                    "POSTGRES_PWD": {
                      "isOptional": true,
                      "description": "Postgres password (reference).",
                      "defaultValue": "${{Postgres.POSTGRES_PASSWORD}}"
                    },
                    "POSTGRES_USER": {
                      "isOptional": true,
                      "description": "Postgres user (needs CREATE DATABASE).",
                      "defaultValue": "${{Postgres.PGUSER}}"
                    },
                    "POSTGRES_SEEDS": {
                      "isOptional": true,
                      "description": "Postgres host.",
                      "defaultValue": "${{Postgres.RAILWAY_PRIVATE_DOMAIN}}"
                    },
                    "TEMPORAL_ADDRESS": {
                      "isOptional": true,
                      "description": "Address the setup script uses to create the namespace.",
                      "defaultValue": "127.0.0.1:7233"
                    },
                    "DYNAMIC_CONFIG_FILE_PATH": {
                      "isOptional": true,
                      "description": "Dynamic config shipped in the image.",
                      "defaultValue": "config/dynamicconfig/docker.yaml"
                    },
                    "TEMPORAL_BROADCAST_ADDRESS": {
                      "isOptional": true,
                      "description": "Single-node membership address.",
                      "defaultValue": "127.0.0.1"
                    },
                    "RAILWAY_DEPLOYMENT_DRAINING_SECONDS": {
                      "isOptional": true,
                      "description": "Clean shutdown on redeploy.",
                      "defaultValue": "30"
                    }
                  },
                  "networking": {
                    "tcpProxies": {},
                    "serviceDomains": {}
                  }
                },
                "0c942951-9088-56fc-bf26-12951982d462": {
                  "icon": "https://devicons.railway.app/i/postgresql.svg",
                  "name": "Postgres",
                  "deploy": {
                    "restartPolicyType": "ON_FAILURE",
                    "restartPolicyMaxRetries": 10
                  },
                  "source": {
                    "image": "ghcr.io/railwayapp-templates/postgres-ssl:18"
                  },
                  "variables": {
                    "PGDATA": {
                      "isOptional": true,
                      "description": "Location where the database will be initialized",
                      "defaultValue": "/var/lib/postgresql/data/pgdata"
                    },
                    "PGHOST": {
                      "isOptional": true,
                      "description": "Railway Private Domain Name.",
                      "defaultValue": "${{RAILWAY_PRIVATE_DOMAIN}}"
                    },
                    "PGPORT": {
                      "isOptional": true,
                      "description": "Port to connect to Postgres.",
                      "defaultValue": "5432"
                    },
                    "PGUSER": {
                      "isOptional": true,
                      "description": "Required variable for Data panel",
                      "defaultValue": "${{ POSTGRES_USER }}"
                    },
                    "PGDATABASE": {
                      "isOptional": true,
                      "description": "Required variable for the data panel.",
                      "defaultValue": "${{POSTGRES_DB}}"
                    },
                    "PGPASSWORD": {
                      "isOptional": true,
                      "description": "Required variable for Data panel",
                      "defaultValue": "${{POSTGRES_PASSWORD}}"
                    },
                    "POSTGRES_DB": {
                      "isOptional": true,
                      "description": "Default database created when image is started (PostHog's database name).",
                      "defaultValue": "posthog"
                    },
                    "DATABASE_URL": {
                      "isOptional": true,
                      "description": "URL to connect to Postgres database.",
                      "defaultValue": "postgresql://${{PGUSER}}:${{POSTGRES_PASSWORD}}@${{RAILWAY_PRIVATE_DOMAIN}}:5432/${{PGDATABASE}}"
                    },
                    "POSTGRES_USER": {
                      "isOptional": true,
                      "description": "User to connect to Postgres DB",
                      "defaultValue": "postgres"
                    },
                    "SSL_CERT_DAYS": {
                      "isOptional": true,
                      "description": "SSL certificate expiry in days.",
                      "defaultValue": "820"
                    },
                    "POSTGRES_PASSWORD": {
                      "isOptional": true,
                      "description": "Password to connect to DB",
                      "defaultValue": "{{POSTGRES_PASSWORD}}"
                    },
                    "RAILWAY_DEPLOYMENT_DRAINING_SECONDS": {
                      "isOptional": true,
                      "description": "Allow Postgres to cleanly shut down",
                      "defaultValue": "60"
                    }
                  },
                  "networking": {
                    "tcpProxies": {},
                    "serviceDomains": {}
                  },
                  "volumeMounts": {
                    "decc7c99-15ff-5d79-a169-1cd5f76fe1c6": {
                      "mountPath": "/var/lib/postgresql/data"
                    }
                  }
                },
                "12affaf3-70e7-5d06-957b-264d465f6fb3": {
                  "icon": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/svg/seaweedfs.svg",
                  "name": "seaweedfs",
                  "build": {
                    "builder": "DOCKERFILE"
                  },
                  "deploy": {
                    "healthcheckPath": "/healthz",
                    "restartPolicyType": "ON_FAILURE",
                    "healthcheckTimeout": 300,
                    "restartPolicyMaxRetries": 10
                  },
                  "source": {
                    "repo": "baranberkay96/posthog-railway",
                    "branch": "main",
                    "rootDirectory": "/services/seaweedfs"
                  },
                  "variables": {
                    "PORT": {
                      "isOptional": true,
                      "description": "S3 port; /healthz is the healthcheck.",
                      "defaultValue": "8333"
                    },
                    "S3_PORT": {
                      "isOptional": true,
                      "description": "S3 gateway port.",
                      "defaultValue": "8333"
                    },
                    "S3_BUCKETS": {
                      "isOptional": true,
                      "description": "Buckets created at start (idempotent).",
                      "defaultValue": "posthog,ai-blobs"
                    },
                    "AWS_ACCESS_KEY_ID": {
                      "isOptional": true,
                      "description": "S3 access key (admin identity).",
                      "defaultValue": "{{AWS_ACCESS_KEY_ID}}"
                    },
                    "AWS_SECRET_ACCESS_KEY": {
                      "isOptional": true,
                      "description": "S3 secret key.",
                      "defaultValue": "{{AWS_SECRET_ACCESS_KEY}}"
                    },
                    "RAILWAY_DEPLOYMENT_DRAINING_SECONDS": {
                      "isOptional": true,
                      "description": "Clean shutdown on redeploy.",
                      "defaultValue": "30"
                    }
                  },
                  "networking": {
                    "tcpProxies": {},
                    "serviceDomains": {}
                  },
                  "volumeMounts": {
                    "cfa82237-0f00-5c73-91c7-577fa97d2f1a": {
                      "mountPath": "/data"
                    }
                  }
                },
                "1862acef-486f-5c37-bd63-6b63172c6c2e": {
                  "icon": "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/caddy.svg",
                  "name": "proxy",
                  "build": {
                    "builder": "DOCKERFILE"
                  },
                  "deploy": {
                    "healthcheckPath": "/_proxy/health",
                    "restartPolicyType": "ALWAYS",
                    "healthcheckTimeout": 120
                  },
                  "source": {
                    "repo": "baranberkay96/posthog-railway",
                    "branch": "main",
                    "rootDirectory": "/services/proxy"
                  },
                  "variables": {
                    "PORT": {
                      "isOptional": true,
                      "description": "Caddy listen port (public domain target).",
                      "defaultValue": "8080"
                    },
                    "WEB_UPSTREAM": {
                      "isOptional": true,
                      "description": "Django web app.",
                      "defaultValue": "${{web.RAILWAY_PRIVATE_DOMAIN}}:8000"
                    },
                    "CAPTURE_UPSTREAM": {
                      "isOptional": true,
                      "description": "Event capture (/e, /i/v0, /batch, /capture).",
                      "defaultValue": "${{capture.RAILWAY_PRIVATE_DOMAIN}}:3000"
                    },
                    "PLUGINS_UPSTREAM": {
                      "isOptional": true,
                      "description": "Webhook sources (/public/webhooks, /public/m).",
                      "defaultValue": "${{plugins.RAILWAY_PRIVATE_DOMAIN}}:6738"
                    },
                    "CAPTURE_AI_UPSTREAM": {
                      "isOptional": true,
                      "description": "LLM analytics capture (/i/v0/ai; ai process of the capture service).",
                      "defaultValue": "${{capture.RAILWAY_PRIVATE_DOMAIN}}:3001"
                    },
                    "HYPERCACHE_UPSTREAM": {
                      "isOptional": true,
                      "description": "Surveys and remote config (/surveys, /array).",
                      "defaultValue": "${{hypercache-server.RAILWAY_PRIVATE_DOMAIN}}:3002"
                    },
                    "LIVESTREAM_UPSTREAM": {
                      "isOptional": true,
                      "description": "Live events stream (/livestream).",
                      "defaultValue": "${{livestream.RAILWAY_PRIVATE_DOMAIN}}:8080"
                    },
                    "CAPTURE_LOGS_UPSTREAM": {
                      "isOptional": true,
                      "description": "OTLP logs/traces/metrics capture (/i/v1/logs, /i/v1/traces, /i/v1/metrics).",
                      "defaultValue": "${{capture-logs.RAILWAY_PRIVATE_DOMAIN}}:4318"
                    },
                    "FEATURE_FLAGS_UPSTREAM": {
                      "isOptional": true,
                      "description": "Feature flags (/flags, local evaluation).",
                      "defaultValue": "${{feature-flags.RAILWAY_PRIVATE_DOMAIN}}:3001"
                    },
                    "OBJECTSTORAGE_UPSTREAM": {
                      "isOptional": true,
                      "description": "Presigned object downloads (/posthog/*).",
                      "defaultValue": "${{seaweedfs.RAILWAY_PRIVATE_DOMAIN}}:8333"
                    },
                    "REPLAY_CAPTURE_UPSTREAM": {
                      "isOptional": true,
                      "description": "Session replay capture (/s; recordings process of the capture service).",
                      "defaultValue": "${{capture.RAILWAY_PRIVATE_DOMAIN}}:3002"
                    }
                  },
                  "networking": {
                    "tcpProxies": {},
                    "serviceDomains": {
                      "<hasDomain>:8080": {
                        "port": 8080
                      }
                    }
                  }
                },
                "1f2d4f91-c9d1-5f8d-b2a4-9f3f07122ac6": {
                  "icon": "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/browserless.svg",
                  "name": "browserless",
                  "deploy": {
                    "restartPolicyType": "ALWAYS"
                  },
                  "source": {
                    "image": "ghcr.io/browserless/chromium:v2.57.0"
                  },
                  "variables": {
                    "HOST": {
                      "isOptional": true,
                      "description": "Listen on all interfaces (dual-stack).",
                      "defaultValue": "::"
                    },
                    "PORT": {
                      "isOptional": true,
                      "description": "HTTP/WebSocket port.",
                      "defaultValue": "3000"
                    },
                    "DEBUG": {
                      "isOptional": true,
                      "description": "Silence debug namespaces (upstream hobby value).",
                      "defaultValue": "-*"
                    },
                    "TOKEN": {
                      "isOptional": true,
                      "description": "Browserless API token (separate from Django's SECRET_KEY).",
                      "defaultValue": "{{TOKEN}}"
                    },
                    "LOG_LEVEL": {
                      "isOptional": true,
                      "description": "Log level (upstream hobby value).",
                      "defaultValue": "warn"
                    }
                  },
                  "networking": {
                    "tcpProxies": {},
                    "serviceDomains": {}
                  }
                },
                "25d5116d-0b39-502c-b520-539747be53a5": {
                  "icon": "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/posthog.svg",
                  "name": "plugins",
                  "build": {
                    "builder": "DOCKERFILE"
                  },
                  "deploy": {
                    "healthcheckPath": "/_health",
                    "restartPolicyType": "ALWAYS",
                    "healthcheckTimeout": 1200
                  },
                  "source": {
                    "repo": "baranberkay96/posthog-railway",
                    "branch": "main",
                    "rootDirectory": "/services/posthog-node"
                  },
                  "variables": {
                    "PORT": {
                      "isOptional": true,
                      "description": "Node HTTP server port (HTTP_SERVER_PORT default); /_health is the healthcheck.",
                      "defaultValue": "6738"
                    },
                    "SITE_URL": {
                      "isOptional": true,
                      "description": "Public URL of PostHog.",
                      "defaultValue": "${{web.SITE_URL}}"
                    },
                    "REDIS_URL": {
                      "isOptional": true,
                      "description": "Redis connection string.",
                      "defaultValue": "${{Redis.REDIS_URL}}"
                    },
                    "SECRET_KEY": {
                      "isOptional": true,
                      "description": "Must match web.",
                      "defaultValue": "${{web.SECRET_KEY}}"
                    },
                    "KAFKA_HOSTS": {
                      "isOptional": true,
                      "description": "Kafka (Redpanda) bootstrap server.",
                      "defaultValue": "${{kafka.RAILWAY_PRIVATE_DOMAIN}}:9092"
                    },
                    "DATABASE_URL": {
                      "isOptional": true,
                      "description": "Postgres connection string.",
                      "defaultValue": "${{Postgres.DATABASE_URL}}"
                    },
                    "CDP_REDIS_HOST": {
                      "isOptional": true,
                      "description": "Redis host for CDP state (function health, rate limits).",
                      "defaultValue": "${{Redis.REDISHOST}}"
                    },
                    "CDP_REDIS_PORT": {
                      "isOptional": true,
                      "description": "Redis port.",
                      "defaultValue": "6379"
                    },
                    "LOGS_REDIS_TLS": {
                      "isOptional": true,
                      "description": "No TLS on the private network.",
                      "defaultValue": "false"
                    },
                    "CDP_VALKEY_HOST": {
                      "isOptional": true,
                      "description": "Not read by the pinned node build. Newer builds dual-write CDP state to a Valkey host and refuse to start without one; it points at Redis so an upgrade keeps working (the hobby compose runs a separate Valkey).",
                      "defaultValue": "${{Redis.REDISHOST}}"
                    },
                    "CDP_VALKEY_PORT": {
                      "isOptional": true,
                      "description": "Port for CDP_VALKEY_HOST.",
                      "defaultValue": "6379"
                    },
                    "CLICKHOUSE_HOST": {
                      "isOptional": true,
                      "description": "ClickHouse host.",
                      "defaultValue": "${{clickhouse.RAILWAY_PRIVATE_DOMAIN}}"
                    },
                    "CLICKHOUSE_USER": {
                      "isOptional": true,
                      "description": "ClickHouse user.",
                      "defaultValue": "default"
                    },
                    "LOGS_REDIS_HOST": {
                      "isOptional": true,
                      "description": "Redis for logs-product state. The pinned node build does not pass LOGS_REDIS_PASSWORD to this pool, so the full URL (with password) goes here; ioredis accepts it.",
                      "defaultValue": "${{Redis.REDIS_URL}}"
                    },
                    "LOGS_REDIS_PORT": {
                      "isOptional": true,
                      "description": "Redis port.",
                      "defaultValue": "6379"
                    },
                    "TRACES_REDIS_TLS": {
                      "isOptional": true,
                      "description": "No TLS on the private network.",
                      "defaultValue": "false"
                    },
                    "CLICKHOUSE_SECURE": {
                      "isOptional": true,
                      "description": "Plain TCP inside the private network.",
                      "defaultValue": "false"
                    },
                    "CLICKHOUSE_VERIFY": {
                      "isOptional": true,
                      "description": "No TLS verification.",
                      "defaultValue": "false"
                    },
                    "TRACES_REDIS_HOST": {
                      "isOptional": true,
                      "description": "Redis for traces-product state. Full URL with password, as for LOGS_REDIS_HOST.",
                      "defaultValue": "${{Redis.REDIS_URL}}"
                    },
                    "TRACES_REDIS_PORT": {
                      "isOptional": true,
                      "description": "Redis port.",
                      "defaultValue": "6379"
                    },
                    "CDP_REDIS_PASSWORD": {
                      "isOptional": true,
                      "description": "Redis password (reference).",
                      "defaultValue": "${{Redis.REDIS_PASSWORD}}"
                    },
                    "CDP_VALKEY_PASSWORD": {
                      "isOptional": true,
                      "description": "Password for CDP_VALKEY_HOST (reference).",
                      "defaultValue": "${{Redis.REDIS_PASSWORD}}"
                    },
                    "CLICKHOUSE_DATABASE": {
                      "isOptional": true,
                      "description": "ClickHouse database.",
                      "defaultValue": "posthog"
                    },
                    "CLICKHOUSE_PASSWORD": {
                      "isOptional": true,
                      "description": "ClickHouse password (reference).",
                      "defaultValue": "${{clickhouse.CLICKHOUSE_PASSWORD}}"
                    },
                    "LOGS_REDIS_PASSWORD": {
                      "isOptional": true,
                      "description": "Redis password (reference).",
                      "defaultValue": "${{Redis.REDIS_PASSWORD}}"
                    },
                    "ENCRYPTION_SALT_KEYS": {
                      "isOptional": true,
                      "description": "Must match web (decrypts encrypted function inputs).",
                      "defaultValue": "${{web.ENCRYPTION_SALT_KEYS}}"
                    },
                    "PERSONS_DATABASE_URL": {
                      "isOptional": true,
                      "description": "Persons live in the main database (hobby layout).",
                      "defaultValue": "${{Postgres.DATABASE_URL}}"
                    },
                    "TRACES_REDIS_PASSWORD": {
                      "isOptional": true,
                      "description": "Redis password (reference).",
                      "defaultValue": "${{Redis.REDIS_PASSWORD}}"
                    },
                    "OBJECT_STORAGE_ENABLED": {
                      "isOptional": true,
                      "description": "Use object storage.",
                      "defaultValue": "true"
                    },
                    "OBJECT_STORAGE_ENDPOINT": {
                      "isOptional": true,
                      "description": "SeaweedFS S3 endpoint.",
                      "defaultValue": "http://${{seaweedfs.RAILWAY_PRIVATE_DOMAIN}}:8333"
                    },
                    "NODEJS_CAPABILITY_GROUPS": {
                      "isOptional": true,
                      "description": "Capabilities of this process: the default plugin-server set plus traces ingestion (replaces upstream's ingestion-logs and ingestion-traces services).",
                      "defaultValue": "cdp_workflows,realtime_cohorts,logs,traces,feature_flags"
                    },
                    "OBJECT_STORAGE_ACCESS_KEY_ID": {
                      "isOptional": true,
                      "description": "Object storage access key (reference).",
                      "defaultValue": "${{seaweedfs.AWS_ACCESS_KEY_ID}}"
                    },
                    "OBJECT_STORAGE_PUBLIC_ENDPOINT": {
                      "isOptional": true,
                      "description": "Public base URL for presigned links.",
                      "defaultValue": "${{web.SITE_URL}}"
                    },
                    "BEHAVIORAL_COHORTS_DATABASE_URL": {
                      "isOptional": true,
                      "description": "Behavioral cohorts live in the main database (hobby layout).",
                      "defaultValue": "${{Postgres.DATABASE_URL}}"
                    },
                    "OBJECT_STORAGE_SECRET_ACCESS_KEY": {
                      "isOptional": true,
                      "description": "Object storage secret key (reference).",
                      "defaultValue": "${{seaweedfs.AWS_SECRET_ACCESS_KEY}}"
                    }
                  },
                  "networking": {
                    "tcpProxies": {},
                    "serviceDomains": {}
                  }
                },
                "37eef1a2-c758-5a07-b1c6-817d3a21025d": {
                  "icon": "https://cdn.jsdelivr.net/gh/redpanda-data/console@master/frontend/public/favicon.svg",
                  "name": "kafka",
                  "build": {
                    "builder": "DOCKERFILE"
                  },
                  "deploy": {
                    "healthcheckPath": "/v1/status/ready",
                    "restartPolicyType": "ON_FAILURE",
                    "healthcheckTimeout": 300,
                    "restartPolicyMaxRetries": 10
                  },
                  "source": {
                    "repo": "baranberkay96/posthog-railway",
                    "branch": "main",
                    "rootDirectory": "/services/kafka"
                  },
                  "variables": {
                    "PORT": {
                      "isOptional": true,
                      "description": "Admin API port; /v1/status/ready is the healthcheck.",
                      "defaultValue": "9644"
                    },
                    "REDPANDA_SMP": {
                      "isOptional": true,
                      "description": "CPU cores Redpanda uses.",
                      "defaultValue": "1"
                    },
                    "REDPANDA_MEMORY": {
                      "isOptional": true,
                      "description": "Memory Redpanda allocates (upstream hobby uses 3G).",
                      "defaultValue": "1G"
                    },
                    "KAFKA_LOG_RETENTION_MS": {
                      "isOptional": true,
                      "description": "Topic retention (24 h). Kafka is a buffer here; ClickHouse holds the data.",
                      "defaultValue": "86400000"
                    },
                    "RAILWAY_DEPLOYMENT_DRAINING_SECONDS": {
                      "isOptional": true,
                      "description": "Clean shutdown on redeploy.",
                      "defaultValue": "30"
                    }
                  },
                  "networking": {
                    "tcpProxies": {},
                    "serviceDomains": {}
                  },
                  "volumeMounts": {
                    "ca18308c-9569-5ec5-a4cd-7da1463652ef": {
                      "mountPath": "/var/lib/redpanda/data"
                    }
                  }
                },
                "3da79bd1-b542-5be3-9ebd-f09730eb81e4": {
                  "icon": "https://cdn.jsdelivr.net/gh/apache/zookeeper@master/zookeeper-website/public/images/logo.svg",
                  "name": "zookeeper",
                  "deploy": {
                    "startCommand": "/bin/bash -c \"mkdir -p /data/datalog && exec /docker-entrypoint.sh zkServer.sh start-foreground\"",
                    "healthcheckPath": "/commands/ruok",
                    "restartPolicyType": "ON_FAILURE",
                    "healthcheckTimeout": 300,
                    "restartPolicyMaxRetries": 10
                  },
                  "source": {
                    "image": "zookeeper:3.9.6"
                  },
                  "variables": {
                    "PORT": {
                      "isOptional": true,
                      "description": "ZooKeeper AdminServer port; /commands/ruok is the healthcheck.",
                      "defaultValue": "8080"
                    },
                    "ZK_SERVER_HEAP": {
                      "isOptional": true,
                      "description": "JVM heap in MB (image default 1000); ClickHouse's coordination data is small.",
                      "defaultValue": "256"
                    },
                    "ZOO_DATA_LOG_DIR": {
                      "isOptional": true,
                      "description": "Transaction log on the volume (Railway allows one volume per service).",
                      "defaultValue": "/data/datalog"
                    },
                    "ZOO_AUTOPURGE_PURGEINTERVAL": {
                      "isOptional": true,
                      "description": "Purge old snapshots hourly (upstream hobby value).",
                      "defaultValue": "1"
                    },
                    "ZOO_AUTOPURGE_SNAPRETAINCOUNT": {
                      "isOptional": true,
                      "description": "Snapshots to keep (upstream hobby value).",
                      "defaultValue": "3"
                    },
                    "RAILWAY_DEPLOYMENT_DRAINING_SECONDS": {
                      "isOptional": true,
                      "description": "Clean shutdown on redeploy.",
                      "defaultValue": "15"
                    }
                  },
                  "networking": {
                    "tcpProxies": {},
                    "serviceDomains": {}
                  },
                  "volumeMounts": {
                    "7fdc36dc-7577-504a-a132-0e78eea1b130": {
                      "mountPath": "/data"
                    }
                  }
                },
                "3ef8bbf4-61fd-51e2-b955-51e378628422": {
                  "icon": "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/posthog.svg",
                  "name": "property-defs",
                  "build": {
                    "builder": "DOCKERFILE"
                  },
                  "deploy": {
                    "healthcheckPath": "/_readiness",
                    "restartPolicyType": "ALWAYS",
                    "healthcheckTimeout": 1200
                  },
                  "source": {
                    "repo": "baranberkay96/posthog-railway",
                    "branch": "main",
                    "rootDirectory": "/services/property-defs"
                  },
                  "variables": {
                    "PORT": {
                      "isOptional": true,
                      "description": "HTTP port of the events process (/_readiness).",
                      "defaultValue": "3301"
                    },
                    "SKIP_READS": {
                      "isOptional": true,
                      "description": "Read existing definitions.",
                      "defaultValue": "false"
                    },
                    "FILTER_MODE": {
                      "isOptional": true,
                      "description": "Process all teams unless opted out.",
                      "defaultValue": "opt-out"
                    },
                    "KAFKA_HOSTS": {
                      "isOptional": true,
                      "description": "Kafka bootstrap server.",
                      "defaultValue": "${{kafka.RAILWAY_PRIVATE_DOMAIN}}:9092"
                    },
                    "SKIP_WRITES": {
                      "isOptional": true,
                      "description": "Write definitions.",
                      "defaultValue": "false"
                    },
                    "DATABASE_URL": {
                      "isOptional": true,
                      "description": "Postgres connection string.",
                      "defaultValue": "${{Postgres.DATABASE_URL}}"
                    }
                  },
                  "networking": {
                    "tcpProxies": {},
                    "serviceDomains": {}
                  }
                },
                "42910f4b-d18b-5756-9ebe-80ffa12ba805": {
                  "icon": "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/posthog.svg",
                  "name": "capture-logs",
                  "deploy": {
                    "healthcheckPath": "/_readiness",
                    "restartPolicyType": "ALWAYS",
                    "healthcheckTimeout": 1200
                  },
                  "source": {
                    "image": "ghcr.io/posthog/posthog/capture-logs:sha-04cdf1c"
                  },
                  "variables": {
                    "PORT": {
                      "isOptional": true,
                      "description": "Management port (/_readiness, /_liveness, metrics); Railway healthcheck target.",
                      "defaultValue": "8080"
                    },
                    "RUST_LOG": {
                      "isOptional": true,
                      "description": "Log level.",
                      "defaultValue": "info,rdkafka=warn"
                    },
                    "BIND_HOST": {
                      "isOptional": true,
                      "description": "OTLP listen address (dual-stack).",
                      "defaultValue": "::"
                    },
                    "BIND_PORT": {
                      "isOptional": true,
                      "description": "OTLP HTTP port.",
                      "defaultValue": "4318"
                    },
                    "JWT_SECRET": {
                      "isOptional": true,
                      "description": "Secret for capture-logs JWT handling (upstream compose ships a placeholder string).",
                      "defaultValue": "{{JWT_SECRET}}"
                    },
                    "KAFKA_HOSTS": {
                      "isOptional": true,
                      "description": "Kafka bootstrap server.",
                      "defaultValue": "${{kafka.RAILWAY_PRIVATE_DOMAIN}}:9092"
                    },
                    "KAFKA_TOPIC": {
                      "isOptional": true,
                      "description": "Logs topic.",
                      "defaultValue": "logs_ingestion"
                    },
                    "RUST_BACKTRACE": {
                      "isOptional": true,
                      "description": "Backtraces on panic.",
                      "defaultValue": "1"
                    },
                    "KAFKA_METRICS_TOPIC": {
                      "isOptional": true,
                      "description": "Metrics topic.",
                      "defaultValue": "metrics_ingestion"
                    },
                    "MANAGEMENT_BIND_PORT": {
                      "isOptional": true,
                      "description": "Management port.",
                      "defaultValue": "8080"
                    },
                    "RAILWAY_DEPLOYMENT_DRAINING_SECONDS": {
                      "isOptional": true,
                      "description": "Short drain on redeploy.",
                      "defaultValue": "15"
                    }
                  },
                  "networking": {
                    "tcpProxies": {},
                    "serviceDomains": {}
                  }
                },
                "4dea4ac8-2d8c-5221-a893-1a779606eeb8": {
                  "icon": "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/posthog.svg",
                  "name": "hypercache-server",
                  "deploy": {
                    "healthcheckPath": "/_readiness",
                    "restartPolicyType": "ALWAYS",
                    "healthcheckTimeout": 1200
                  },
                  "source": {
                    "image": "ghcr.io/posthog/posthog/hypercache-server:sha-14bcc04"
                  },
                  "variables": {
                    "PORT": {
                      "isOptional": true,
                      "description": "HTTP port; /_readiness is the healthcheck.",
                      "defaultValue": "3002"
                    },
                    "ADDRESS": {
                      "isOptional": true,
                      "description": "Bind address (dual-stack).",
                      "defaultValue": "[::]:3002"
                    },
                    "RUST_LOG": {
                      "isOptional": true,
                      "description": "Log level.",
                      "defaultValue": "info"
                    },
                    "REDIS_URL": {
                      "isOptional": true,
                      "description": "Redis connection string.",
                      "defaultValue": "${{Redis.REDIS_URL}}"
                    },
                    "AWS_ACCESS_KEY_ID": {
                      "isOptional": true,
                      "description": "Object storage access key (reference).",
                      "defaultValue": "${{seaweedfs.AWS_ACCESS_KEY_ID}}"
                    },
                    "AWS_SECRET_ACCESS_KEY": {
                      "isOptional": true,
                      "description": "Object storage secret key (reference).",
                      "defaultValue": "${{seaweedfs.AWS_SECRET_ACCESS_KEY}}"
                    },
                    "OBJECT_STORAGE_ENDPOINT": {
                      "isOptional": true,
                      "description": "HyperCache S3 tier endpoint (SeaweedFS).",
                      "defaultValue": "http://${{seaweedfs.RAILWAY_PRIVATE_DOMAIN}}:8333"
                    },
                    "RAILWAY_DEPLOYMENT_DRAINING_SECONDS": {
                      "isOptional": true,
                      "description": "Short drain on redeploy.",
                      "defaultValue": "15"
                    }
                  },
                  "networking": {
                    "tcpProxies": {},
                    "serviceDomains": {}
                  }
                },
                "582f9442-e84b-5963-bd6b-55c4ab7afd64": {
                  "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 --maxmemory $REDIS_MAXMEMORY --maxmemory-policy allkeys-lru\"",
                    "restartPolicyType": "ON_FAILURE",
                    "restartPolicyMaxRetries": 10
                  },
                  "source": {
                    "image": "redis:7.2.16-alpine"
                  },
                  "variables": {
                    "REDISHOST": {
                      "isOptional": true,
                      "description": "Private network hostname of the Redis service, only resolvable from services in the same environment",
                      "defaultValue": "${{RAILWAY_PRIVATE_DOMAIN}}"
                    },
                    "REDISPORT": {
                      "isOptional": true,
                      "description": "Port that Redis listens on",
                      "defaultValue": "6379"
                    },
                    "REDISUSER": {
                      "isOptional": true,
                      "description": "Username for authenticating with Redis",
                      "defaultValue": "default"
                    },
                    "REDIS_URL": {
                      "isOptional": true,
                      "description": "Connection string for connecting to Redis using the private network",
                      "defaultValue": "redis://${{ REDISUSER }}:${{ REDIS_PASSWORD }}@${{ REDISHOST }}:${{ REDISPORT }}"
                    },
                    "REDISPASSWORD": {
                      "isOptional": true,
                      "description": "Alias of REDIS_PASSWORD for clients that expect the unseparated name",
                      "defaultValue": "${{REDIS_PASSWORD}}"
                    },
                    "REDIS_PASSWORD": {
                      "isOptional": true,
                      "description": "Randomly generated password for authenticating with Redis",
                      "defaultValue": "{{REDIS_PASSWORD}}"
                    },
                    "REDIS_MAXMEMORY": {
                      "isOptional": true,
                      "description": "Memory cap with LRU eviction (hobby compose uses 200mb).",
                      "defaultValue": "512mb"
                    }
                  },
                  "networking": {
                    "tcpProxies": {},
                    "serviceDomains": {}
                  },
                  "volumeMounts": {
                    "8e85fac6-6ee7-57ee-bd58-6d2edce28c30": {
                      "mountPath": "/data"
                    }
                  }
                },
                "6c588eea-b09d-5624-8cad-a15e44bbc3fe": {
                  "icon": "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/posthog.svg",
                  "name": "capture",
                  "build": {
                    "builder": "DOCKERFILE"
                  },
                  "deploy": {
                    "healthcheckPath": "/_readiness",
                    "restartPolicyType": "ALWAYS",
                    "healthcheckTimeout": 1200
                  },
                  "source": {
                    "repo": "baranberkay96/posthog-railway",
                    "branch": "main",
                    "rootDirectory": "/services/capture"
                  },
                  "variables": {
                    "PORT": {
                      "isOptional": true,
                      "description": "Events capture port; /_readiness is the healthcheck.",
                      "defaultValue": "3000"
                    },
                    "RUST_LOG": {
                      "isOptional": true,
                      "description": "Log level.",
                      "defaultValue": "info,rdkafka=warn"
                    },
                    "REDIS_URL": {
                      "isOptional": true,
                      "description": "Redis (quota limits, event restrictions).",
                      "defaultValue": "${{Redis.REDIS_URL}}"
                    },
                    "KAFKA_HOSTS": {
                      "isOptional": true,
                      "description": "Kafka bootstrap server.",
                      "defaultValue": "${{kafka.RAILWAY_PRIVATE_DOMAIN}}:9092"
                    },
                    "CAPTURE_AI_PORT": {
                      "isOptional": true,
                      "description": "Port of the LLM analytics (ai) process.",
                      "defaultValue": "3001"
                    },
                    "CAPTURE_EVENTS_PORT": {
                      "isOptional": true,
                      "description": "Port of the events process.",
                      "defaultValue": "3000"
                    },
                    "CAPTURE_REPLAY_PORT": {
                      "isOptional": true,
                      "description": "Port of the session replay (recordings) process.",
                      "defaultValue": "3002"
                    },
                    "CAPTURE_AI_LANE_TOPIC": {
                      "isOptional": true,
                      "description": "Topic for LLM analytics events. The main topic, because the pinned Node build does not consume PostHog's separate AI lane (events_plugin_ingestion_ai); change only together with a Node image that does.",
                      "defaultValue": "events_plugin_ingestion"
                    },
                    "RAILWAY_DEPLOYMENT_DRAINING_SECONDS": {
                      "isOptional": true,
                      "description": "Short drain on redeploy.",
                      "defaultValue": "15"
                    },
                    "KAFKA_INGESTION_PRODUCER_METADATA_BROKER_LIST": {
                      "isOptional": true,
                      "description": "Kafka metadata broker list for the producer.",
                      "defaultValue": "${{kafka.RAILWAY_PRIVATE_DOMAIN}}:9092"
                    }
                  },
                  "networking": {
                    "tcpProxies": {},
                    "serviceDomains": {}
                  }
                },
                "74f86a40-5dc4-5a62-b5f8-d5c37905d799": {
                  "icon": "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/posthog.svg",
                  "name": "temporal-django-worker",
                  "deploy": {
                    "startCommand": "./bin/temporal-django-worker",
                    "restartPolicyType": "ALWAYS"
                  },
                  "source": {
                    "image": "posthog/posthog:sha-716405ddea318758493221f26e844512757c7927"
                  },
                  "variables": {
                    "SITE_URL": {
                      "isOptional": true,
                      "description": "Same as web: Public URL of PostHog (the proxy domain).",
                      "defaultValue": "${{web.SITE_URL}}"
                    },
                    "REDIS_URL": {
                      "isOptional": true,
                      "description": "Same as web: Redis for cache, Celery broker and locks.",
                      "defaultValue": "${{web.REDIS_URL}}"
                    },
                    "DEPLOYMENT": {
                      "isOptional": true,
                      "description": "Same as web: Deployment type; hobby keeps persons in the main database.",
                      "defaultValue": "${{web.DEPLOYMENT}}"
                    },
                    "SECRET_KEY": {
                      "isOptional": true,
                      "description": "Same as web: Django secret key; signs sessions and tokens.",
                      "defaultValue": "${{web.SECRET_KEY}}"
                    },
                    "CDP_API_URL": {
                      "isOptional": true,
                      "description": "Same as web: Internal URL of the plugins (CDP) service.",
                      "defaultValue": "${{web.CDP_API_URL}}"
                    },
                    "KAFKA_HOSTS": {
                      "isOptional": true,
                      "description": "Same as web: Kafka (Redpanda) bootstrap server.",
                      "defaultValue": "${{web.KAFKA_HOSTS}}"
                    },
                    "DATABASE_URL": {
                      "isOptional": true,
                      "description": "Same as web: Postgres connection string.",
                      "defaultValue": "${{web.DATABASE_URL}}"
                    },
                    "OPENAI_MODEL": {
                      "isOptional": true,
                      "description": "Same as web: Model used for OpenAI-backed assists.",
                      "defaultValue": "${{web.OPENAI_MODEL}}"
                    },
                    "TEMPORAL_HOST": {
                      "isOptional": true,
                      "description": "Same as web: Temporal frontend host (batch exports, data warehouse, workflows).",
                      "defaultValue": "${{web.TEMPORAL_HOST}}"
                    },
                    "OPENAI_API_KEY": {
                      "isOptional": true,
                      "description": "Same as web: Optional OpenAI key for SQL/regex assist.",
                      "defaultValue": "${{web.OPENAI_API_KEY}}"
                    },
                    "PERSONHOG_ADDR": {
                      "isOptional": true,
                      "description": "Same as web: gRPC address of the personhog router.",
                      "defaultValue": "${{web.PERSONHOG_ADDR}}"
                    },
                    "CLICKHOUSE_HOST": {
                      "isOptional": true,
                      "description": "Same as web: ClickHouse host (private network).",
                      "defaultValue": "${{web.CLICKHOUSE_HOST}}"
                    },
                    "CLICKHOUSE_USER": {
                      "isOptional": true,
                      "description": "Same as web: ClickHouse admin user used for queries and migrations.",
                      "defaultValue": "${{web.CLICKHOUSE_USER}}"
                    },
                    "IS_BEHIND_PROXY": {
                      "isOptional": true,
                      "description": "Same as web: Trust X-Forwarded-* from the Caddy proxy / Railway edge.",
                      "defaultValue": "${{web.IS_BEHIND_PROXY}}"
                    },
                    "OPENAI_BASE_URL": {
                      "isOptional": true,
                      "description": "Same as web: OpenAI-compatible API base URL.",
                      "defaultValue": "${{web.OPENAI_BASE_URL}}"
                    },
                    "ANTHROPIC_API_KEY": {
                      "isOptional": true,
                      "description": "Same as web: Optional Anthropic key for PostHog AI.",
                      "defaultValue": "${{web.ANTHROPIC_API_KEY}}"
                    },
                    "BROWSERLESS_TOKEN": {
                      "isOptional": true,
                      "description": "Browserless token (reference).",
                      "defaultValue": "${{browserless.TOKEN}}"
                    },
                    "CLICKHOUSE_SECURE": {
                      "isOptional": true,
                      "description": "Same as web: Plain TCP inside the private network.",
                      "defaultValue": "${{web.CLICKHOUSE_SECURE}}"
                    },
                    "CLICKHOUSE_VERIFY": {
                      "isOptional": true,
                      "description": "Same as web: No TLS verification (no TLS on the private network).",
                      "defaultValue": "${{web.CLICKHOUSE_VERIFY}}"
                    },
                    "OTEL_SDK_DISABLED": {
                      "isOptional": true,
                      "description": "Same as web: No OpenTelemetry export from Django.",
                      "defaultValue": "${{web.OTEL_SDK_DISABLED}}"
                    },
                    "PERSONHOG_ENABLED": {
                      "isOptional": true,
                      "description": "Same as web: Read persons through personhog, as upstream hobby does.",
                      "defaultValue": "${{web.PERSONHOG_ENABLED}}"
                    },
                    "RECORDING_API_URL": {
                      "isOptional": true,
                      "description": "Same as web: Internal URL of the recording API (replay playback).",
                      "defaultValue": "${{web.RECORDING_API_URL}}"
                    },
                    "BROWSERLESS_CDP_URL": {
                      "isOptional": true,
                      "description": "Browserless CDP endpoint for image exports.",
                      "defaultValue": "ws://${{browserless.RAILWAY_PRIVATE_DOMAIN}}:3000"
                    },
                    "CLICKHOUSE_API_USER": {
                      "isOptional": true,
                      "description": "Same as web: ClickHouse user for API queries.",
                      "defaultValue": "${{web.CLICKHOUSE_API_USER}}"
                    },
                    "CLICKHOUSE_APP_USER": {
                      "isOptional": true,
                      "description": "Same as web: ClickHouse user for app queries.",
                      "defaultValue": "${{web.CLICKHOUSE_APP_USER}}"
                    },
                    "CLICKHOUSE_DATABASE": {
                      "isOptional": true,
                      "description": "Same as web: ClickHouse database PostHog uses.",
                      "defaultValue": "${{web.CLICKHOUSE_DATABASE}}"
                    },
                    "CLICKHOUSE_PASSWORD": {
                      "isOptional": true,
                      "description": "Same as web: ClickHouse default-user password.",
                      "defaultValue": "${{web.CLICKHOUSE_PASSWORD}}"
                    },
                    "INTERNAL_API_SECRET": {
                      "isOptional": true,
                      "description": "Same as web: Shared secret for internal service-to-service calls.",
                      "defaultValue": "${{web.INTERNAL_API_SECRET}}"
                    },
                    "API_QUERIES_PER_TEAM": {
                      "isOptional": true,
                      "description": "Same as web: Concurrent API query limit per team (upstream hobby value).",
                      "defaultValue": "${{web.API_QUERIES_PER_TEAM}}"
                    },
                    "ENCRYPTION_SALT_KEYS": {
                      "isOptional": true,
                      "description": "Same as web: Salt for encrypted fields (integration secrets).",
                      "defaultValue": "${{web.ENCRYPTION_SALT_KEYS}}"
                    },
                    "PERSONS_DB_READER_URL": {
                      "isOptional": true,
                      "description": "Same as web: Persons database reader (same Postgres database).",
                      "defaultValue": "${{web.PERSONS_DB_READER_URL}}"
                    },
                    "PERSONS_DB_WRITER_URL": {
                      "isOptional": true,
                      "description": "Same as web: Persons database (same Postgres database in this stack).",
                      "defaultValue": "${{web.PERSONS_DB_WRITER_URL}}"
                    },
                    "INTERNAL_REQUEST_TOKEN": {
                      "isOptional": true,
                      "description": "Same as web: Token for Django to feature-flags calls.",
                      "defaultValue": "${{web.INTERNAL_REQUEST_TOKEN}}"
                    },
                    "OBJECT_STORAGE_ENABLED": {
                      "isOptional": true,
                      "description": "Same as web: Use S3 object storage for exports and media.",
                      "defaultValue": "${{web.OBJECT_STORAGE_ENABLED}}"
                    },
                    "CLICKHOUSE_API_PASSWORD": {
                      "isOptional": true,
                      "description": "Same as web: Password of the api user.",
                      "defaultValue": "${{web.CLICKHOUSE_API_PASSWORD}}"
                    },
                    "CLICKHOUSE_APP_PASSWORD": {
                      "isOptional": true,
                      "description": "Same as web: Password of the app user.",
                      "defaultValue": "${{web.CLICKHOUSE_APP_PASSWORD}}"
                    },
                    "HEATMAP_BROWSERLESS_URL": {
                      "isOptional": true,
                      "description": "Browserless HTTP endpoint for heatmap screenshots.",
                      "defaultValue": "http://${{browserless.RAILWAY_PRIVATE_DOMAIN}}:3000"
                    },
                    "OBJECT_STORAGE_ENDPOINT": {
                      "isOptional": true,
                      "description": "Same as web: SeaweedFS S3 endpoint for exports, media and AI blobs.",
                      "defaultValue": "${{web.OBJECT_STORAGE_ENDPOINT}}"
                    },
                    "FEATURE_FLAGS_SERVICE_URL": {
                      "isOptional": true,
                      "description": "Same as web: Internal URL of the Rust feature-flags service.",
                      "defaultValue": "${{web.FEATURE_FLAGS_SERVICE_URL}}"
                    },
                    "HEATMAP_BROWSERLESS_TOKEN": {
                      "isOptional": true,
                      "description": "Browserless token (reference).",
                      "defaultValue": "${{browserless.TOKEN}}"
                    },
                    "CLICKHOUSE_DICT_READER_USER": {
                      "isOptional": true,
                      "description": "Same as web: Read-only user ClickHouse dictionaries authenticate as.",
                      "defaultValue": "${{web.CLICKHOUSE_DICT_READER_USER}}"
                    },
                    "DISABLE_SECURE_SSL_REDIRECT": {
                      "isOptional": true,
                      "description": "Same as web: TLS is terminated by Railway; no redirect loop.",
                      "defaultValue": "${{web.DISABLE_SECURE_SSL_REDIRECT}}"
                    },
                    "CLICKHOUSE_LOGS_CLUSTER_HOST": {
                      "isOptional": true,
                      "description": "Same as web: ClickHouse host for the logs product (same server).",
                      "defaultValue": "${{web.CLICKHOUSE_LOGS_CLUSTER_HOST}}"
                    },
                    "OBJECT_STORAGE_ACCESS_KEY_ID": {
                      "isOptional": true,
                      "description": "Same as web: Object storage access key.",
                      "defaultValue": "${{web.OBJECT_STORAGE_ACCESS_KEY_ID}}"
                    },
                    "CLICKHOUSE_LOGS_CLUSTER_SECURE": {
                      "isOptional": true,
                      "description": "Same as web: Plain TCP for the logs cluster connection.",
                      "defaultValue": "${{web.CLICKHOUSE_LOGS_CLUSTER_SECURE}}"
                    },
                    "OBJECT_STORAGE_PUBLIC_ENDPOINT": {
                      "isOptional": true,
                      "description": "Same as web: Base URL for presigned downloads (proxied under /posthog).",
                      "defaultValue": "${{web.OBJECT_STORAGE_PUBLIC_ENDPOINT}}"
                    },
                    "CLICKHOUSE_DICT_READER_PASSWORD": {
                      "isOptional": true,
                      "description": "Same as web: Password of the dict_reader user.",
                      "defaultValue": "${{web.CLICKHOUSE_DICT_READER_PASSWORD}}"
                    },
                    "OBJECT_STORAGE_FORCE_PATH_STYLE": {
                      "isOptional": true,
                      "description": "Same as web: SeaweedFS needs path-style requests.",
                      "defaultValue": "${{web.OBJECT_STORAGE_FORCE_PATH_STYLE}}"
                    },
                    "CLICKHOUSE_LOGS_CLUSTER_PASSWORD": {
                      "isOptional": true,
                      "description": "Same as web: Password for the logs cluster connection (default user).",
                      "defaultValue": "${{web.CLICKHOUSE_LOGS_CLUSTER_PASSWORD}}"
                    },
                    "OBJECT_STORAGE_SECRET_ACCESS_KEY": {
                      "isOptional": true,
                      "description": "Same as web: Object storage secret key.",
                      "defaultValue": "${{web.OBJECT_STORAGE_SECRET_ACCESS_KEY}}"
                    },
                    "SESSION_RECORDING_V2_S3_ENDPOINT": {
                      "isOptional": true,
                      "description": "Same as web: SeaweedFS S3 endpoint for session recordings.",
                      "defaultValue": "${{web.SESSION_RECORDING_V2_S3_ENDPOINT}}"
                    },
                    "RAILWAY_DEPLOYMENT_DRAINING_SECONDS": {
                      "isOptional": true,
                      "description": "Let running activities finish on redeploy.",
                      "defaultValue": "60"
                    },
                    "SESSION_RECORDING_V2_S3_ACCESS_KEY_ID": {
                      "isOptional": true,
                      "description": "Same as web: Recording store access key.",
                      "defaultValue": "${{web.SESSION_RECORDING_V2_S3_ACCESS_KEY_ID}}"
                    },
                    "SESSION_RECORDING_V2_S3_SECRET_ACCESS_KEY": {
                      "isOptional": true,
                      "description": "Same as web: Recording store secret key.",
                      "defaultValue": "${{web.SESSION_RECORDING_V2_S3_SECRET_ACCESS_KEY}}"
                    },
                    "HEATMAP_BROWSERLESS_SCREENSHOT_COOKIES_ENABLED": {
                      "isOptional": true,
                      "description": "Do not forward cookies to heatmap screenshots (upstream default).",
                      "defaultValue": "false"
                    }
                  },
                  "networking": {
                    "tcpProxies": {},
                    "serviceDomains": {}
                  }
                },
                "7b6dada1-46a6-5ac3-a905-28efc354160c": {
                  "icon": "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/posthog.svg",
                  "name": "feature-flags",
                  "build": {
                    "builder": "DOCKERFILE"
                  },
                  "deploy": {
                    "healthcheckPath": "/_readiness",
                    "restartPolicyType": "ALWAYS",
                    "healthcheckTimeout": 1200
                  },
                  "source": {
                    "repo": "baranberkay96/posthog-railway",
                    "branch": "main",
                    "rootDirectory": "/services/feature-flags"
                  },
                  "variables": {
                    "PORT": {
                      "isOptional": true,
                      "description": "HTTP port; /_readiness is the healthcheck.",
                      "defaultValue": "3001"
                    },
                    "ADDRESS": {
                      "isOptional": true,
                      "description": "Bind address (dual-stack).",
                      "defaultValue": "[::]:3001"
                    },
                    "RUST_LOG": {
                      "isOptional": true,
                      "description": "Log level.",
                      "defaultValue": "info"
                    },
                    "REDIS_URL": {
                      "isOptional": true,
                      "description": "Redis for team and flag caches.",
                      "defaultValue": "${{Redis.REDIS_URL}}"
                    },
                    "AWS_ACCESS_KEY_ID": {
                      "isOptional": true,
                      "description": "Object storage access key (reference).",
                      "defaultValue": "${{seaweedfs.AWS_ACCESS_KEY_ID}}"
                    },
                    "READ_DATABASE_URL": {
                      "isOptional": true,
                      "description": "Postgres (reader).",
                      "defaultValue": "${{Postgres.DATABASE_URL}}"
                    },
                    "WRITE_DATABASE_URL": {
                      "isOptional": true,
                      "description": "Postgres (writer).",
                      "defaultValue": "${{Postgres.DATABASE_URL}}"
                    },
                    "AWS_SECRET_ACCESS_KEY": {
                      "isOptional": true,
                      "description": "Object storage secret key (reference).",
                      "defaultValue": "${{seaweedfs.AWS_SECRET_ACCESS_KEY}}"
                    },
                    "COOKIELESS_REDIS_HOST": {
                      "isOptional": true,
                      "description": "Cookieless-mode Redis. The service builds redis://HOST:PORT from this value, so the credentials are embedded in the host part.",
                      "defaultValue": "default:${{Redis.REDIS_PASSWORD}}@${{Redis.REDISHOST}}"
                    },
                    "COOKIELESS_REDIS_PORT": {
                      "isOptional": true,
                      "description": "Redis port.",
                      "defaultValue": "6379"
                    },
                    "INTERNAL_REQUEST_TOKEN": {
                      "isOptional": true,
                      "description": "Must match web (flag test evaluation).",
                      "defaultValue": "${{web.INTERNAL_REQUEST_TOKEN}}"
                    },
                    "OBJECT_STORAGE_ENDPOINT": {
                      "isOptional": true,
                      "description": "HyperCache S3 tier endpoint (SeaweedFS).",
                      "defaultValue": "http://${{seaweedfs.RAILWAY_PRIVATE_DOMAIN}}:8333"
                    },
                    "PERSONS_READ_DATABASE_URL": {
                      "isOptional": true,
                      "description": "Persons database reader.",
                      "defaultValue": "${{Postgres.DATABASE_URL}}"
                    },
                    "PERSONS_WRITE_DATABASE_URL": {
                      "isOptional": true,
                      "description": "Persons database (main database in the hobby layout).",
                      "defaultValue": "${{Postgres.DATABASE_URL}}"
                    },
                    "RAILWAY_DEPLOYMENT_DRAINING_SECONDS": {
                      "isOptional": true,
                      "description": "Short drain on redeploy.",
                      "defaultValue": "15"
                    }
                  },
                  "networking": {
                    "tcpProxies": {},
                    "serviceDomains": {}
                  }
                },
                "7b813f4d-4a20-554f-976c-f1dbd250b77b": {
                  "icon": "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/posthog.svg",
                  "name": "worker",
                  "deploy": {
                    "startCommand": "./bin/docker-worker-celery --with-scheduler",
                    "restartPolicyType": "ALWAYS"
                  },
                  "source": {
                    "image": "posthog/posthog:sha-716405ddea318758493221f26e844512757c7927"
                  },
                  "variables": {
                    "SITE_URL": {
                      "isOptional": true,
                      "description": "Same as web: Public URL of PostHog (the proxy domain).",
                      "defaultValue": "${{web.SITE_URL}}"
                    },
                    "REDIS_URL": {
                      "isOptional": true,
                      "description": "Same as web: Redis for cache, Celery broker and locks.",
                      "defaultValue": "${{web.REDIS_URL}}"
                    },
                    "DEPLOYMENT": {
                      "isOptional": true,
                      "description": "Same as web: Deployment type; hobby keeps persons in the main database.",
                      "defaultValue": "${{web.DEPLOYMENT}}"
                    },
                    "SECRET_KEY": {
                      "isOptional": true,
                      "description": "Same as web: Django secret key; signs sessions and tokens.",
                      "defaultValue": "${{web.SECRET_KEY}}"
                    },
                    "CDP_API_URL": {
                      "isOptional": true,
                      "description": "Same as web: Internal URL of the plugins (CDP) service.",
                      "defaultValue": "${{web.CDP_API_URL}}"
                    },
                    "KAFKA_HOSTS": {
                      "isOptional": true,
                      "description": "Same as web: Kafka (Redpanda) bootstrap server.",
                      "defaultValue": "${{web.KAFKA_HOSTS}}"
                    },
                    "DATABASE_URL": {
                      "isOptional": true,
                      "description": "Same as web: Postgres connection string.",
                      "defaultValue": "${{web.DATABASE_URL}}"
                    },
                    "OPENAI_MODEL": {
                      "isOptional": true,
                      "description": "Same as web: Model used for OpenAI-backed assists.",
                      "defaultValue": "${{web.OPENAI_MODEL}}"
                    },
                    "TEMPORAL_HOST": {
                      "isOptional": true,
                      "description": "Same as web: Temporal frontend host (batch exports, data warehouse, workflows).",
                      "defaultValue": "${{web.TEMPORAL_HOST}}"
                    },
                    "OPENAI_API_KEY": {
                      "isOptional": true,
                      "description": "Same as web: Optional OpenAI key for SQL/regex assist.",
                      "defaultValue": "${{web.OPENAI_API_KEY}}"
                    },
                    "PERSONHOG_ADDR": {
                      "isOptional": true,
                      "description": "Same as web: gRPC address of the personhog router.",
                      "defaultValue": "${{web.PERSONHOG_ADDR}}"
                    },
                    "CLICKHOUSE_HOST": {
                      "isOptional": true,
                      "description": "Same as web: ClickHouse host (private network).",
                      "defaultValue": "${{web.CLICKHOUSE_HOST}}"
                    },
                    "CLICKHOUSE_USER": {
                      "isOptional": true,
                      "description": "Same as web: ClickHouse admin user used for queries and migrations.",
                      "defaultValue": "${{web.CLICKHOUSE_USER}}"
                    },
                    "IS_BEHIND_PROXY": {
                      "isOptional": true,
                      "description": "Same as web: Trust X-Forwarded-* from the Caddy proxy / Railway edge.",
                      "defaultValue": "${{web.IS_BEHIND_PROXY}}"
                    },
                    "OPENAI_BASE_URL": {
                      "isOptional": true,
                      "description": "Same as web: OpenAI-compatible API base URL.",
                      "defaultValue": "${{web.OPENAI_BASE_URL}}"
                    },
                    "WEB_CONCURRENCY": {
                      "isOptional": true,
                      "description": "Celery worker processes. Upstream default is one per CPU, which on Railway means the host's CPU count.",
                      "defaultValue": "2"
                    },
                    "ANTHROPIC_API_KEY": {
                      "isOptional": true,
                      "description": "Same as web: Optional Anthropic key for PostHog AI.",
                      "defaultValue": "${{web.ANTHROPIC_API_KEY}}"
                    },
                    "BROWSERLESS_TOKEN": {
                      "isOptional": true,
                      "description": "Browserless token (reference).",
                      "defaultValue": "${{browserless.TOKEN}}"
                    },
                    "CLICKHOUSE_SECURE": {
                      "isOptional": true,
                      "description": "Same as web: Plain TCP inside the private network.",
                      "defaultValue": "${{web.CLICKHOUSE_SECURE}}"
                    },
                    "CLICKHOUSE_VERIFY": {
                      "isOptional": true,
                      "description": "Same as web: No TLS verification (no TLS on the private network).",
                      "defaultValue": "${{web.CLICKHOUSE_VERIFY}}"
                    },
                    "OTEL_SDK_DISABLED": {
                      "isOptional": true,
                      "description": "Same as web: No OpenTelemetry export from Django.",
                      "defaultValue": "${{web.OTEL_SDK_DISABLED}}"
                    },
                    "PERSONHOG_ENABLED": {
                      "isOptional": true,
                      "description": "Same as web: Read persons through personhog, as upstream hobby does.",
                      "defaultValue": "${{web.PERSONHOG_ENABLED}}"
                    },
                    "RECORDING_API_URL": {
                      "isOptional": true,
                      "description": "Same as web: Internal URL of the recording API (replay playback).",
                      "defaultValue": "${{web.RECORDING_API_URL}}"
                    },
                    "BROWSERLESS_CDP_URL": {
                      "isOptional": true,
                      "description": "Browserless CDP endpoint for image exports.",
                      "defaultValue": "ws://${{browserless.RAILWAY_PRIVATE_DOMAIN}}:3000"
                    },
                    "CLICKHOUSE_API_USER": {
                      "isOptional": true,
                      "description": "Same as web: ClickHouse user for API queries.",
                      "defaultValue": "${{web.CLICKHOUSE_API_USER}}"
                    },
                    "CLICKHOUSE_APP_USER": {
                      "isOptional": true,
                      "description": "Same as web: ClickHouse user for app queries.",
                      "defaultValue": "${{web.CLICKHOUSE_APP_USER}}"
                    },
                    "CLICKHOUSE_DATABASE": {
                      "isOptional": true,
                      "description": "Same as web: ClickHouse database PostHog uses.",
                      "defaultValue": "${{web.CLICKHOUSE_DATABASE}}"
                    },
                    "CLICKHOUSE_PASSWORD": {
                      "isOptional": true,
                      "description": "Same as web: ClickHouse default-user password.",
                      "defaultValue": "${{web.CLICKHOUSE_PASSWORD}}"
                    },
                    "INTERNAL_API_SECRET": {
                      "isOptional": true,
                      "description": "Same as web: Shared secret for internal service-to-service calls.",
                      "defaultValue": "${{web.INTERNAL_API_SECRET}}"
                    },
                    "API_QUERIES_PER_TEAM": {
                      "isOptional": true,
                      "description": "Same as web: Concurrent API query limit per team (upstream hobby value).",
                      "defaultValue": "${{web.API_QUERIES_PER_TEAM}}"
                    },
                    "ENCRYPTION_SALT_KEYS": {
                      "isOptional": true,
                      "description": "Same as web: Salt for encrypted fields (integration secrets).",
                      "defaultValue": "${{web.ENCRYPTION_SALT_KEYS}}"
                    },
                    "PERSONS_DB_READER_URL": {
                      "isOptional": true,
                      "description": "Same as web: Persons database reader (same Postgres database).",
                      "defaultValue": "${{web.PERSONS_DB_READER_URL}}"
                    },
                    "PERSONS_DB_WRITER_URL": {
                      "isOptional": true,
                      "description": "Same as web: Persons database (same Postgres database in this stack).",
                      "defaultValue": "${{web.PERSONS_DB_WRITER_URL}}"
                    },
                    "INTERNAL_REQUEST_TOKEN": {
                      "isOptional": true,
                      "description": "Same as web: Token for Django to feature-flags calls.",
                      "defaultValue": "${{web.INTERNAL_REQUEST_TOKEN}}"
                    },
                    "OBJECT_STORAGE_ENABLED": {
                      "isOptional": true,
                      "description": "Same as web: Use S3 object storage for exports and media.",
                      "defaultValue": "${{web.OBJECT_STORAGE_ENABLED}}"
                    },
                    "CLICKHOUSE_API_PASSWORD": {
                      "isOptional": true,
                      "description": "Same as web: Password of the api user.",
                      "defaultValue": "${{web.CLICKHOUSE_API_PASSWORD}}"
                    },
                    "CLICKHOUSE_APP_PASSWORD": {
                      "isOptional": true,
                      "description": "Same as web: Password of the app user.",
                      "defaultValue": "${{web.CLICKHOUSE_APP_PASSWORD}}"
                    },
                    "HEATMAP_BROWSERLESS_URL": {
                      "isOptional": true,
                      "description": "Browserless HTTP endpoint for heatmap screenshots.",
                      "defaultValue": "http://${{browserless.RAILWAY_PRIVATE_DOMAIN}}:3000"
                    },
                    "OBJECT_STORAGE_ENDPOINT": {
                      "isOptional": true,
                      "description": "Same as web: SeaweedFS S3 endpoint for exports, media and AI blobs.",
                      "defaultValue": "${{web.OBJECT_STORAGE_ENDPOINT}}"
                    },
                    "FEATURE_FLAGS_SERVICE_URL": {
                      "isOptional": true,
                      "description": "Same as web: Internal URL of the Rust feature-flags service.",
                      "defaultValue": "${{web.FEATURE_FLAGS_SERVICE_URL}}"
                    },
                    "HEATMAP_BROWSERLESS_TOKEN": {
                      "isOptional": true,
                      "description": "Browserless token (reference).",
                      "defaultValue": "${{browserless.TOKEN}}"
                    },
                    "CLICKHOUSE_DICT_READER_USER": {
                      "isOptional": true,
                      "description": "Same as web: Read-only user ClickHouse dictionaries authenticate as.",
                      "defaultValue": "${{web.CLICKHOUSE_DICT_READER_USER}}"
                    },
                    "DISABLE_SECURE_SSL_REDIRECT": {
                      "isOptional": true,
                      "description": "Same as web: TLS is terminated by Railway; no redirect loop.",
                      "defaultValue": "${{web.DISABLE_SECURE_SSL_REDIRECT}}"
                    },
                    "CLICKHOUSE_LOGS_CLUSTER_HOST": {
                      "isOptional": true,
                      "description": "Same as web: ClickHouse host for the logs product (same server).",
                      "defaultValue": "${{web.CLICKHOUSE_LOGS_CLUSTER_HOST}}"
                    },
                    "OBJECT_STORAGE_ACCESS_KEY_ID": {
                      "isOptional": true,
                      "description": "Same as web: Object storage access key.",
                      "defaultValue": "${{web.OBJECT_STORAGE_ACCESS_KEY_ID}}"
                    },
                    "POSTHOG_SKIP_MIGRATION_CHECKS": {
                      "isOptional": true,
                      "description": "Migrations run in web's pre-deploy step; do not block on them here (upstream hobby setting).",
                      "defaultValue": "1"
                    },
                    "CLICKHOUSE_LOGS_CLUSTER_SECURE": {
                      "isOptional": true,
                      "description": "Same as web: Plain TCP for the logs cluster connection.",
                      "defaultValue": "${{web.CLICKHOUSE_LOGS_CLUSTER_SECURE}}"
                    },
                    "OBJECT_STORAGE_PUBLIC_ENDPOINT": {
                      "isOptional": true,
                      "description": "Same as web: Base URL for presigned downloads (proxied under /posthog).",
                      "defaultValue": "${{web.OBJECT_STORAGE_PUBLIC_ENDPOINT}}"
                    },
                    "CLICKHOUSE_DICT_READER_PASSWORD": {
                      "isOptional": true,
                      "description": "Same as web: Password of the dict_reader user.",
                      "defaultValue": "${{web.CLICKHOUSE_DICT_READER_PASSWORD}}"
                    },
                    "OBJECT_STORAGE_FORCE_PATH_STYLE": {
                      "isOptional": true,
                      "description": "Same as web: SeaweedFS needs path-style requests.",
                      "defaultValue": "${{web.OBJECT_STORAGE_FORCE_PATH_STYLE}}"
                    },
                    "CLICKHOUSE_LOGS_CLUSTER_PASSWORD": {
                      "isOptional": true,
                      "description": "Same as web: Password for the logs cluster connection (default user).",
                      "defaultValue": "${{web.CLICKHOUSE_LOGS_CLUSTER_PASSWORD}}"
                    },
                    "OBJECT_STORAGE_SECRET_ACCESS_KEY": {
                      "isOptional": true,
                      "description": "Same as web: Object storage secret key.",
                      "defaultValue": "${{web.OBJECT_STORAGE_SECRET_ACCESS_KEY}}"
                    },
                    "SESSION_RECORDING_V2_S3_ENDPOINT": {
                      "isOptional": true,
                      "description": "Same as web: SeaweedFS S3 endpoint for session recordings.",
                      "defaultValue": "${{web.SESSION_RECORDING_V2_S3_ENDPOINT}}"
                    },
                    "RAILWAY_DEPLOYMENT_DRAINING_SECONDS": {
                      "isOptional": true,
                      "description": "Let running Celery tasks finish on redeploy.",
                      "defaultValue": "60"
                    },
                    "SESSION_RECORDING_V2_S3_ACCESS_KEY_ID": {
                      "isOptional": true,
                      "description": "Same as web: Recording store access key.",
                      "defaultValue": "${{web.SESSION_RECORDING_V2_S3_ACCESS_KEY_ID}}"
                    },
                    "SESSION_RECORDING_V2_S3_SECRET_ACCESS_KEY": {
                      "isOptional": true,
                      "description": "Same as web: Recording store secret key.",
                      "defaultValue": "${{web.SESSION_RECORDING_V2_S3_SECRET_ACCESS_KEY}}"
                    },
                    "HEATMAP_BROWSERLESS_SCREENSHOT_COOKIES_ENABLED": {
                      "isOptional": true,
                      "description": "Do not forward cookies to heatmap screenshots (upstream default).",
                      "defaultValue": "false"
                    }
                  },
                  "networking": {
                    "tcpProxies": {},
                    "serviceDomains": {}
                  }
                },
                "7e6c08d3-78f1-5844-8bd3-25f0719716dc": {
                  "icon": "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/posthog.svg",
                  "name": "personhog",
                  "build": {
                    "builder": "DOCKERFILE"
                  },
                  "deploy": {
                    "healthcheckPath": "/_readiness",
                    "restartPolicyType": "ALWAYS",
                    "healthcheckTimeout": 1200
                  },
                  "source": {
                    "repo": "baranberkay96/posthog-railway",
                    "branch": "main",
                    "rootDirectory": "/services/personhog"
                  },
                  "variables": {
                    "PORT": {
                      "isOptional": true,
                      "description": "Router metrics/health port; /_readiness is the healthcheck.",
                      "defaultValue": "9101"
                    },
                    "RUST_LOG": {
                      "isOptional": true,
                      "description": "Log level.",
                      "defaultValue": "info"
                    },
                    "BACKEND_TIMEOUT_MS": {
                      "isOptional": true,
                      "description": "Router-to-replica call timeout.",
                      "defaultValue": "5000"
                    },
                    "PRIMARY_DATABASE_URL": {
                      "isOptional": true,
                      "description": "Persons database (main database in the hobby layout).",
                      "defaultValue": "${{Postgres.DATABASE_URL}}"
                    }
                  },
                  "networking": {
                    "tcpProxies": {},
                    "serviceDomains": {}
                  }
                },
                "8f65aa52-45f3-558d-a998-29c2eb897312": {
                  "icon": "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/posthog.svg",
                  "name": "recordings",
                  "build": {
                    "builder": "DOCKERFILE"
                  },
                  "deploy": {
                    "healthcheckPath": "/_health",
                    "restartPolicyType": "ALWAYS",
                    "healthcheckTimeout": 1200
                  },
                  "source": {
                    "repo": "baranberkay96/posthog-railway",
                    "branch": "main",
                    "rootDirectory": "/services/posthog-node"
                  },
                  "variables": {
                    "PORT": {
                      "isOptional": true,
                      "description": "Node HTTP server port (HTTP_SERVER_PORT default); /_health is the healthcheck.",
                      "defaultValue": "6738"
                    },
                    "REDIS_URL": {
                      "isOptional": true,
                      "description": "Redis connection string.",
                      "defaultValue": "${{Redis.REDIS_URL}}"
                    },
                    "KAFKA_HOSTS": {
                      "isOptional": true,
                      "description": "Kafka (Redpanda) bootstrap server.",
                      "defaultValue": "${{kafka.RAILWAY_PRIVATE_DOMAIN}}:9092"
                    },
                    "DATABASE_URL": {
                      "isOptional": true,
                      "description": "Postgres connection string.",
                      "defaultValue": "${{Postgres.DATABASE_URL}}"
                    },
                    "NODE_PROCESSES": {
                      "isOptional": true,
                      "description": "Node processes in this service (mode:port). web calls the recording API on 6739.",
                      "defaultValue": "recordings-blob-ingestion-v2:6738 recording-api:6739"
                    },
                    "CLICKHOUSE_HOST": {
                      "isOptional": true,
                      "description": "ClickHouse host.",
                      "defaultValue": "${{clickhouse.RAILWAY_PRIVATE_DOMAIN}}"
                    },
                    "CLICKHOUSE_USER": {
                      "isOptional": true,
                      "description": "ClickHouse user.",
                      "defaultValue": "default"
                    },
                    "CLICKHOUSE_SECURE": {
                      "isOptional": true,
                      "description": "Plain TCP inside the private network.",
                      "defaultValue": "false"
                    },
                    "CLICKHOUSE_VERIFY": {
                      "isOptional": true,
                      "description": "No TLS verification.",
                      "defaultValue": "false"
                    },
                    "CLICKHOUSE_DATABASE": {
                      "isOptional": true,
                      "description": "ClickHouse database.",
                      "defaultValue": "posthog"
                    },
                    "CLICKHOUSE_PASSWORD": {
                      "isOptional": true,
                      "description": "ClickHouse password (reference).",
                      "defaultValue": "${{clickhouse.CLICKHOUSE_PASSWORD}}"
                    },
                    "INTERNAL_API_SECRET": {
                      "isOptional": true,
                      "description": "Must match web (X-Internal-Api-Secret on recording API calls).",
                      "defaultValue": "${{web.INTERNAL_API_SECRET}}"
                    },
                    "ENCRYPTION_SALT_KEYS": {
                      "isOptional": true,
                      "description": "Must match web (decrypts encrypted function inputs).",
                      "defaultValue": "${{web.ENCRYPTION_SALT_KEYS}}"
                    },
                    "SESSION_RECORDING_API_REDIS_HOST": {
                      "isOptional": true,
                      "description": "Redis for the recording API. This setting has no password field; ioredis accepts the full URL (with password) here.",
                      "defaultValue": "${{Redis.REDIS_URL}}"
                    },
                    "SESSION_RECORDING_API_REDIS_PORT": {
                      "isOptional": true,
                      "description": "Redis port.",
                      "defaultValue": "6379"
                    },
                    "SESSION_RECORDING_V2_S3_ENDPOINT": {
                      "isOptional": true,
                      "description": "SeaweedFS S3 endpoint for recordings.",
                      "defaultValue": "http://${{seaweedfs.RAILWAY_PRIVATE_DOMAIN}}:8333"
                    },
                    "SESSION_RECORDING_V2_S3_TIMEOUT_MS": {
                      "isOptional": true,
                      "description": "S3 request timeout (upstream hobby value).",
                      "defaultValue": "120000"
                    },
                    "SESSION_RECORDING_V2_S3_ACCESS_KEY_ID": {
                      "isOptional": true,
                      "description": "Recording store access key (reference).",
                      "defaultValue": "${{seaweedfs.AWS_ACCESS_KEY_ID}}"
                    },
                    "SESSION_RECORDING_V2_S3_SECRET_ACCESS_KEY": {
                      "isOptional": true,
                      "description": "Recording store secret key (reference).",
                      "defaultValue": "${{seaweedfs.AWS_SECRET_ACCESS_KEY}}"
                    }
                  },
                  "networking": {
                    "tcpProxies": {},
                    "serviceDomains": {}
                  }
                },
                "b0acac91-f9dc-5d0f-955f-6fd3785ae095": {
                  "icon": "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/clickhouse.svg",
                  "name": "clickhouse",
                  "build": {
                    "builder": "DOCKERFILE"
                  },
                  "deploy": {
                    "healthcheckPath": "/ping",
                    "restartPolicyType": "ON_FAILURE",
                    "healthcheckTimeout": 600,
                    "restartPolicyMaxRetries": 10
                  },
                  "source": {
                    "repo": "baranberkay96/posthog-railway",
                    "branch": "main",
                    "rootDirectory": "/services/clickhouse"
                  },
                  "variables": {
                    "PORT": {
                      "isOptional": true,
                      "description": "HTTP port; /ping is the healthcheck.",
                      "defaultValue": "8123"
                    },
                    "KAFKA_HOSTS": {
                      "isOptional": true,
                      "description": "Brokers for PostHog's Kafka engine tables (named collections).",
                      "defaultValue": "${{kafka.RAILWAY_PRIVATE_DOMAIN}}:9092"
                    },
                    "ZOOKEEPER_HOST": {
                      "isOptional": true,
                      "description": "ZooKeeper host for ON CLUSTER DDL and replicated tables.",
                      "defaultValue": "${{zookeeper.RAILWAY_PRIVATE_DOMAIN}}"
                    },
                    "CLICKHOUSE_PASSWORD": {
                      "isOptional": true,
                      "description": "Password of the default (admin) user. Alphanumeric: PostHog embeds it in SQL.",
                      "defaultValue": "{{CLICKHOUSE_PASSWORD}}"
                    },
                    "CLICKHOUSE_API_PASSWORD": {
                      "isOptional": true,
                      "description": "Password of the api user.",
                      "defaultValue": "{{CLICKHOUSE_API_PASSWORD}}"
                    },
                    "CLICKHOUSE_APP_PASSWORD": {
                      "isOptional": true,
                      "description": "Password of the app user.",
                      "defaultValue": "{{CLICKHOUSE_APP_PASSWORD}}"
                    },
                    "CLICKHOUSE_DICT_READER_PASSWORD": {
                      "isOptional": true,
                      "description": "Password of the read-only dict_reader user.",
                      "defaultValue": "{{CLICKHOUSE_DICT_READER_PASSWORD}}"
                    },
                    "RAILWAY_DEPLOYMENT_DRAINING_SECONDS": {
                      "isOptional": true,
                      "description": "Let ClickHouse flush and stop cleanly.",
                      "defaultValue": "60"
                    }
                  },
                  "networking": {
                    "tcpProxies": {},
                    "serviceDomains": {}
                  },
                  "volumeMounts": {
                    "2d7a79a5-6c11-5e91-8093-f91d01de9c32": {
                      "mountPath": "/var/lib/clickhouse"
                    }
                  }
                },
                "bdb5fdd8-8670-53be-8e34-0b50dc8998ed": {
                  "icon": "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/posthog.svg",
                  "name": "livestream",
                  "deploy": {
                    "healthcheckPath": "/",
                    "restartPolicyType": "ALWAYS",
                    "healthcheckTimeout": 1200
                  },
                  "source": {
                    "image": "ghcr.io/posthog/posthog/livestream:397fc8862e1ca5121a8679f0f686afde88d70b14"
                  },
                  "variables": {
                    "PORT": {
                      "isOptional": true,
                      "description": "HTTP port.",
                      "defaultValue": "8080"
                    },
                    "LIVESTREAM_MMDB_PATH": {
                      "isOptional": true,
                      "description": "GeoLite2 database shipped in the image.",
                      "defaultValue": "/GeoLite2-City.mmdb"
                    },
                    "LIVESTREAM_JWT_SECRET": {
                      "isOptional": true,
                      "description": "Must equal web's SECRET_KEY (signs live-events tokens).",
                      "defaultValue": "${{web.SECRET_KEY}}"
                    },
                    "LIVESTREAM_CONSUMERS_EVENT_TOPIC": {
                      "isOptional": true,
                      "description": "Events topic.",
                      "defaultValue": "events_plugin_ingestion"
                    },
                    "LIVESTREAM_CONSUMERS_EVENT_BROKERS": {
                      "isOptional": true,
                      "description": "Kafka bootstrap server (events).",
                      "defaultValue": "${{kafka.RAILWAY_PRIVATE_DOMAIN}}:9092"
                    },
                    "LIVESTREAM_CONSUMERS_EVENT_GROUP_ID": {
                      "isOptional": true,
                      "description": "Consumer group.",
                      "defaultValue": "livestream"
                    },
                    "LIVESTREAM_CONSUMERS_EVENT_SECURITY_PROTOCOL": {
                      "isOptional": true,
                      "description": "Kafka protocol.",
                      "defaultValue": "PLAINTEXT"
                    },
                    "LIVESTREAM_CONSUMERS_SESSION_RECORDING_TOPIC": {
                      "isOptional": true,
                      "description": "Recording snapshots topic.",
                      "defaultValue": "session_recording_snapshot_item_events"
                    },
                    "LIVESTREAM_CONSUMERS_SESSION_RECORDING_BROKERS": {
                      "isOptional": true,
                      "description": "Kafka bootstrap server (recordings).",
                      "defaultValue": "${{kafka.RAILWAY_PRIVATE_DOMAIN}}:9092"
                    },
                    "LIVESTREAM_CONSUMERS_SESSION_RECORDING_GROUP_ID": {
                      "isOptional": true,
                      "description": "Consumer group.",
                      "defaultValue": "livestream-session-recordings"
                    },
                    "LIVESTREAM_CONSUMERS_SESSION_RECORDING_SECURITY_PROTOCOL": {
                      "isOptional": true,
                      "description": "Kafka protocol.",
                      "defaultValue": "PLAINTEXT"
                    }
                  },
                  "networking": {
                    "tcpProxies": {},
                    "serviceDomains": {}
                  }
                },
                "d0acb8ac-34ef-5945-bbfa-fb356fdd9de5": {
                  "icon": "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/posthog.svg",
                  "name": "cymbal",
                  "build": {
                    "builder": "DOCKERFILE"
                  },
                  "deploy": {
                    "healthcheckPath": "/_readiness",
                    "restartPolicyType": "ALWAYS",
                    "healthcheckTimeout": 1200
                  },
                  "source": {
                    "repo": "baranberkay96/posthog-railway",
                    "branch": "main",
                    "rootDirectory": "/services/cymbal"
                  },
                  "variables": {
                    "PORT": {
                      "isOptional": true,
                      "description": "HTTP port of the processing process; /_readiness is the healthcheck.",
                      "defaultValue": "3302"
                    },
                    "RUST_LOG": {
                      "isOptional": true,
                      "description": "Log level.",
                      "defaultValue": "info"
                    },
                    "BIND_HOST": {
                      "isOptional": true,
                      "description": "Bind address (dual-stack).",
                      "defaultValue": "::"
                    },
                    "BIND_PORT": {
                      "isOptional": true,
                      "description": "HTTP port.",
                      "defaultValue": "3302"
                    },
                    "REDIS_URL": {
                      "isOptional": true,
                      "description": "Redis connection string.",
                      "defaultValue": "${{Redis.REDIS_URL}}"
                    },
                    "KAFKA_HOSTS": {
                      "isOptional": true,
                      "description": "Kafka bootstrap server.",
                      "defaultValue": "${{kafka.RAILWAY_PRIVATE_DOMAIN}}:9092"
                    },
                    "PERSONS_URL": {
                      "isOptional": true,
                      "description": "Persons database (main database).",
                      "defaultValue": "${{Postgres.DATABASE_URL}}"
                    },
                    "DATABASE_URL": {
                      "isOptional": true,
                      "description": "Postgres connection string.",
                      "defaultValue": "${{Postgres.DATABASE_URL}}"
                    },
                    "INTERNAL_API_SECRET": {
                      "isOptional": true,
                      "description": "Must match web.",
                      "defaultValue": "${{web.INTERNAL_API_SECRET}}"
                    },
                    "OBJECT_STORAGE_BUCKET": {
                      "isOptional": true,
                      "description": "Bucket for symbol sets.",
                      "defaultValue": "posthog"
                    },
                    "ISSUE_BUCKETS_REDIS_URL": {
                      "isOptional": true,
                      "description": "Redis for issue rate buckets.",
                      "defaultValue": "${{Redis.REDIS_URL}}"
                    },
                    "OBJECT_STORAGE_ENDPOINT": {
                      "isOptional": true,
                      "description": "SeaweedFS S3 endpoint.",
                      "defaultValue": "http://${{seaweedfs.RAILWAY_PRIVATE_DOMAIN}}:8333"
                    },
                    "OBJECT_STORAGE_ACCESS_KEY_ID": {
                      "isOptional": true,
                      "description": "Access key (reference).",
                      "defaultValue": "${{seaweedfs.AWS_ACCESS_KEY_ID}}"
                    },
                    "OBJECT_STORAGE_FORCE_PATH_STYLE": {
                      "isOptional": true,
                      "description": "SeaweedFS needs path-style requests.",
                      "defaultValue": "true"
                    },
                    "OBJECT_STORAGE_SECRET_ACCESS_KEY": {
                      "isOptional": true,
                      "description": "Secret key (reference).",
                      "defaultValue": "${{seaweedfs.AWS_SECRET_ACCESS_KEY}}"
                    }
                  },
                  "networking": {
                    "tcpProxies": {},
                    "serviceDomains": {}
                  }
                },
                "f1df982e-fa4e-5253-9976-8ec40b2afbab": {
                  "icon": "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/posthog.svg",
                  "name": "ingestion",
                  "build": {
                    "builder": "DOCKERFILE"
                  },
                  "deploy": {
                    "healthcheckPath": "/_health",
                    "restartPolicyType": "ALWAYS",
                    "healthcheckTimeout": 1200
                  },
                  "source": {
                    "repo": "baranberkay96/posthog-railway",
                    "branch": "main",
                    "rootDirectory": "/services/posthog-node"
                  },
                  "variables": {
                    "PORT": {
                      "isOptional": true,
                      "description": "Node HTTP server port (HTTP_SERVER_PORT default); /_health is the healthcheck.",
                      "defaultValue": "6738"
                    },
                    "REDIS_URL": {
                      "isOptional": true,
                      "description": "Redis connection string.",
                      "defaultValue": "${{Redis.REDIS_URL}}"
                    },
                    "KAFKA_HOSTS": {
                      "isOptional": true,
                      "description": "Kafka (Redpanda) bootstrap server.",
                      "defaultValue": "${{kafka.RAILWAY_PRIVATE_DOMAIN}}:9092"
                    },
                    "DATABASE_URL": {
                      "isOptional": true,
                      "description": "Postgres connection string.",
                      "defaultValue": "${{Postgres.DATABASE_URL}}"
                    },
                    "CDP_REDIS_HOST": {
                      "isOptional": true,
                      "description": "Redis host for CDP state (function health, rate limits).",
                      "defaultValue": "${{Redis.REDISHOST}}"
                    },
                    "CDP_REDIS_PORT": {
                      "isOptional": true,
                      "description": "Redis port.",
                      "defaultValue": "6379"
                    },
                    "NODE_PROCESSES": {
                      "isOptional": true,
                      "description": "Node processes in this service (mode:port). A process that exits restarts the service.",
                      "defaultValue": "ingestion-v2-combined:6738 ingestion-errortracking:6739"
                    },
                    "PERSONHOG_ADDR": {
                      "isOptional": true,
                      "description": "personhog router (gRPC).",
                      "defaultValue": "${{personhog.RAILWAY_PRIVATE_DOMAIN}}:50052"
                    },
                    "CLICKHOUSE_HOST": {
                      "isOptional": true,
                      "description": "ClickHouse host.",
                      "defaultValue": "${{clickhouse.RAILWAY_PRIVATE_DOMAIN}}"
                    },
                    "CLICKHOUSE_USER": {
                      "isOptional": true,
                      "description": "ClickHouse user.",
                      "defaultValue": "default"
                    },
                    "AI_BLOB_S3_BUCKET": {
                      "isOptional": true,
                      "description": "Bucket for offloaded multimodal AI payloads.",
                      "defaultValue": "ai-blobs"
                    },
                    "AI_BLOB_S3_PREFIX": {
                      "isOptional": true,
                      "description": "Key prefix for AI blobs.",
                      "defaultValue": "aio/"
                    },
                    "AI_BLOB_S3_REGION": {
                      "isOptional": true,
                      "description": "Region string for the S3 client.",
                      "defaultValue": "us-east-1"
                    },
                    "CLICKHOUSE_SECURE": {
                      "isOptional": true,
                      "description": "Plain TCP inside the private network.",
                      "defaultValue": "false"
                    },
                    "CLICKHOUSE_VERIFY": {
                      "isOptional": true,
                      "description": "No TLS verification.",
                      "defaultValue": "false"
                    },
                    "PERSONHOG_ENABLED": {
                      "isOptional": true,
                      "description": "Read persons through personhog for the AI consumer.",
                      "defaultValue": "true"
                    },
                    "CDP_REDIS_PASSWORD": {
                      "isOptional": true,
                      "description": "Redis password (reference).",
                      "defaultValue": "${{Redis.REDIS_PASSWORD}}"
                    },
                    "AI_BLOB_S3_ENDPOINT": {
                      "isOptional": true,
                      "description": "SeaweedFS S3 endpoint.",
                      "defaultValue": "http://${{seaweedfs.RAILWAY_PRIVATE_DOMAIN}}:8333"
                    },
                    "CLICKHOUSE_DATABASE": {
                      "isOptional": true,
                      "description": "ClickHouse database.",
                      "defaultValue": "posthog"
                    },
                    "CLICKHOUSE_PASSWORD": {
                      "isOptional": true,
                      "description": "ClickHouse password (reference).",
                      "defaultValue": "${{clickhouse.CLICKHOUSE_PASSWORD}}"
                    },
                    "ENCRYPTION_SALT_KEYS": {
                      "isOptional": true,
                      "description": "Must match web (decrypts encrypted function inputs).",
                      "defaultValue": "${{web.ENCRYPTION_SALT_KEYS}}"
                    },
                    "PERSONS_DATABASE_URL": {
                      "isOptional": true,
                      "description": "Persons live in the main database (hobby layout).",
                      "defaultValue": "${{Postgres.DATABASE_URL}}"
                    },
                    "AI_BLOB_OFFLOAD_TEAMS": {
                      "isOptional": true,
                      "description": "Offload AI blobs for all teams.",
                      "defaultValue": "*"
                    },
                    "AI_BLOB_S3_ACCESS_KEY_ID": {
                      "isOptional": true,
                      "description": "Object storage access key (reference).",
                      "defaultValue": "${{seaweedfs.AWS_ACCESS_KEY_ID}}"
                    },
                    "AI_BLOB_S3_SECRET_ACCESS_KEY": {
                      "isOptional": true,
                      "description": "Object storage secret key (reference).",
                      "defaultValue": "${{seaweedfs.AWS_SECRET_ACCESS_KEY}}"
                    },
                    "ERROR_TRACKING_CYMBAL_BASE_URL": {
                      "isOptional": true,
                      "description": "cymbal processing service (error tracking process).",
                      "defaultValue": "http://${{cymbal.RAILWAY_PRIVATE_DOMAIN}}:3302"
                    },
                    "BEHAVIORAL_COHORTS_DATABASE_URL": {
                      "isOptional": true,
                      "description": "Behavioral cohorts live in the main database (hobby layout).",
                      "defaultValue": "${{Postgres.DATABASE_URL}}"
                    },
                    "INGESTION_AI_EVENT_SPLITTING_TEAMS": {
                      "isOptional": true,
                      "description": "Teams to split AI events for (all).",
                      "defaultValue": "*"
                    },
                    "INGESTION_AI_EVENT_SPLITTING_ENABLED": {
                      "isOptional": true,
                      "description": "Write the full LLM analytics events (prompts, outputs) to the ai_events table and keep them out of the events table, as PostHog's AI lane does.",
                      "defaultValue": "true"
                    }
                  },
                  "networking": {
                    "tcpProxies": {},
                    "serviceDomains": {}
                  }
                },
                "f247b859-dae2-5117-8102-47d4c6a7efc2": {
                  "icon": "https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/posthog.svg",
                  "name": "web",
                  "deploy": {
                    "startCommand": "./bin/docker-server",
                    "healthcheckPath": "/_health",
                    "preDeployCommand": [
                      "/bin/bash -c 'for hp in $MIGRATE_WAIT_FOR; do until (exec 3<>/dev/tcp/${hp%:*}/${hp##*:}) 2>/dev/null; do echo \"waiting for $hp\"; sleep 5; done; done; python3 -c \"$(echo aW1wb3J0IGJhc2U2NCwgb3MsIHN5cywgdGltZSwgdXJsbGliLnBhcnNlLCB1cmxsaWIucmVxdWVzdAp1cmwgPSAiaHR0cDovLyVzOjgxMjMvP3F1ZXJ5PSVzIiAlIChvcy5lbnZpcm9uWyJDTElDS0hPVVNFX0hPU1QiXSwgdXJsbGliLnBhcnNlLnF1b3RlKCJTRUxFQ1QgY291bnQoKSBGUk9NIHN5c3RlbS5jbHVzdGVycyBXSEVSRSBjbHVzdGVyID0gJ3Bvc3Rob2cnIikpCmF1dGggPSBiYXNlNjQuYjY0ZW5jb2RlKCgiJXM6JXMiICUgKG9zLmVudmlyb24uZ2V0KCJDTElDS0hPVVNFX1VTRVIiLCAiZGVmYXVsdCIpLCBvcy5lbnZpcm9uWyJDTElDS0hPVVNFX1BBU1NXT1JEIl0pKS5lbmNvZGUoKSkuZGVjb2RlKCkKZm9yIF8gaW4gcmFuZ2UoNjAwKToKICAgIHRyeToKICAgICAgICByZXEgPSB1cmxsaWIucmVxdWVzdC5SZXF1ZXN0KHVybCwgaGVhZGVycz17IkF1dGhvcml6YXRpb24iOiAiQmFzaWMgIiArIGF1dGh9KQogICAgICAgIGlmIGludCh1cmxsaWIucmVxdWVzdC51cmxvcGVuKHJlcSwgdGltZW91dD01KS5yZWFkKCkuc3RyaXAoKSBvciAwKSA+IDA6CiAgICAgICAgICAgIHByaW50KCJDbGlja0hvdXNlIHBvc3Rob2cgY2x1c3RlciByZWFkeSIsIGZsdXNoPVRydWUpCiAgICAgICAgICAgIHN5cy5leGl0KDApCiAgICBleGNlcHQgRXhjZXB0aW9uOgogICAgICAgIHBhc3MKICAgIHByaW50KCJ3YWl0aW5nIGZvciB0aGUgQ2xpY2tIb3VzZSBwb3N0aG9nIGNsdXN0ZXIiLCBmbHVzaD1UcnVlKQogICAgdGltZS5zbGVlcCg1KQpzeXMuZXhpdCgxKQo= | base64 -d)\" && exec ./bin/migrate'"
                    ],
                    "restartPolicyType": "ALWAYS",
                    "healthcheckTimeout": 900,
                    "preDeployTimeoutSeconds": 3600
                  },
                  "source": {
                    "image": "posthog/posthog:sha-716405ddea318758493221f26e844512757c7927"
                  },
                  "variables": {
                    "PORT": {
                      "isOptional": true,
                      "description": "Granian HTTP port; Railway healthcheck probes it.",
                      "defaultValue": "8000"
                    },
                    "SITE_URL": {
                      "isOptional": true,
                      "description": "Public URL of PostHog (the proxy domain). Change it when you add a custom domain to the proxy.",
                      "defaultValue": "https://${{proxy.RAILWAY_PUBLIC_DOMAIN}}"
                    },
                    "REDIS_URL": {
                      "isOptional": true,
                      "description": "Redis for cache, Celery broker and locks.",
                      "defaultValue": "${{Redis.REDIS_URL}}"
                    },
                    "DEPLOYMENT": {
                      "isOptional": true,
                      "description": "Deployment type; hobby keeps persons in the main database and runs persons migrations.",
                      "defaultValue": "hobby"
                    },
                    "SECRET_KEY": {
                      "isOptional": true,
                      "description": "Django secret key (hobby installer format). Generated once; changing it logs everyone out.",
                      "defaultValue": "{{SECRET_KEY}}"
                    },
                    "CDP_API_URL": {
                      "isOptional": true,
                      "description": "Internal URL of the plugins (CDP) service.",
                      "defaultValue": "http://${{plugins.RAILWAY_PRIVATE_DOMAIN}}:6738"
                    },
                    "KAFKA_HOSTS": {
                      "isOptional": true,
                      "description": "Kafka (Redpanda) bootstrap server.",
                      "defaultValue": "${{kafka.RAILWAY_PRIVATE_DOMAIN}}:9092"
                    },
                    "DATABASE_URL": {
                      "isOptional": true,
                      "description": "Postgres connection string (private network).",
                      "defaultValue": "${{Postgres.DATABASE_URL}}"
                    },
                    "OPENAI_MODEL": {
                      "isOptional": true,
                      "description": "Model used for OpenAI-backed assists (upstream default).",
                      "defaultValue": "gpt-4.1-mini"
                    },
                    "TEMPORAL_HOST": {
                      "isOptional": true,
                      "description": "Temporal frontend host (batch exports, data warehouse, workflows).",
                      "defaultValue": "${{temporal.RAILWAY_PRIVATE_DOMAIN}}"
                    },
                    "OPENAI_API_KEY": {
                      "isOptional": true,
                      "description": "Optional: OpenAI API key for SQL and regex assist.",
                      "defaultValue": ""
                    },
                    "PERSONHOG_ADDR": {
                      "isOptional": true,
                      "description": "gRPC address of the personhog router.",
                      "defaultValue": "${{personhog.RAILWAY_PRIVATE_DOMAIN}}:50052"
                    },
                    "CLICKHOUSE_HOST": {
                      "isOptional": true,
                      "description": "ClickHouse host (private network).",
                      "defaultValue": "${{clickhouse.RAILWAY_PRIVATE_DOMAIN}}"
                    },
                    "CLICKHOUSE_USER": {
                      "isOptional": true,
                      "description": "ClickHouse admin user used for queries and migrations.",
                      "defaultValue": "default"
                    },
                    "GRANIAN_WORKERS": {
                      "isOptional": true,
                      "description": "Web worker processes (~1.1 GB RAM each). Upstream default is 4; raise it for more concurrent API/UI requests.",
                      "defaultValue": "2"
                    },
                    "IS_BEHIND_PROXY": {
                      "isOptional": true,
                      "description": "Trust X-Forwarded-* from the Caddy proxy / Railway edge.",
                      "defaultValue": "true"
                    },
                    "LIVESTREAM_HOST": {
                      "isOptional": true,
                      "description": "Public URL of the live events stream (proxied to livestream).",
                      "defaultValue": "${{SITE_URL}}/livestream"
                    },
                    "OPENAI_BASE_URL": {
                      "isOptional": true,
                      "description": "OpenAI-compatible API base URL.",
                      "defaultValue": "https://api.openai.com/v1"
                    },
                    "OPT_OUT_CAPTURE": {
                      "isOptional": true,
                      "description": "Anonymous usage reporting to PostHog Inc. (upstream default). Set true to opt out.",
                      "defaultValue": "false"
                    },
                    "MIGRATE_WAIT_FOR": {
                      "isOptional": true,
                      "description": "host:port list the pre-deploy step waits for before running migrations.",
                      "defaultValue": "${{Postgres.RAILWAY_PRIVATE_DOMAIN}}:5432 ${{clickhouse.RAILWAY_PRIVATE_DOMAIN}}:9000 ${{zookeeper.RAILWAY_PRIVATE_DOMAIN}}:2181 ${{kafka.RAILWAY_PRIVATE_DOMAIN}}:9092 ${{Redis.RAILWAY_PRIVATE_DOMAIN}}:6379"
                    },
                    "ANTHROPIC_API_KEY": {
                      "isOptional": true,
                      "description": "Optional: Anthropic API key to enable PostHog AI. Leave empty to keep AI features off.",
                      "defaultValue": ""
                    },
                    "CLICKHOUSE_SECURE": {
                      "isOptional": true,
                      "description": "Plain TCP inside the private network.",
                      "defaultValue": "false"
                    },
                    "CLICKHOUSE_VERIFY": {
                      "isOptional": true,
                      "description": "No TLS verification (no TLS on the private network).",
                      "defaultValue": "false"
                    },
                    "OTEL_SDK_DISABLED": {
                      "isOptional": true,
                      "description": "No OpenTelemetry export from Django.",
                      "defaultValue": "true"
                    },
                    "OTEL_SERVICE_NAME": {
                      "isOptional": true,
                      "description": "Service name if OpenTelemetry is enabled later.",
                      "defaultValue": "posthog"
                    },
                    "PERSONHOG_ENABLED": {
                      "isOptional": true,
                      "description": "Read persons through personhog, as the upstream hobby stack does.",
                      "defaultValue": "true"
                    },
                    "RECORDING_API_URL": {
                      "isOptional": true,
                      "description": "Internal URL of the recording API (replay playback; second process of the recordings service).",
                      "defaultValue": "http://${{recordings.RAILWAY_PRIVATE_DOMAIN}}:6739"
                    },
                    "CLICKHOUSE_API_USER": {
                      "isOptional": true,
                      "description": "ClickHouse user for API queries.",
                      "defaultValue": "api"
                    },
                    "CLICKHOUSE_APP_USER": {
                      "isOptional": true,
                      "description": "ClickHouse user for app queries.",
                      "defaultValue": "app"
                    },
                    "CLICKHOUSE_DATABASE": {
                      "isOptional": true,
                      "description": "ClickHouse database PostHog uses.",
                      "defaultValue": "posthog"
                    },
                    "CLICKHOUSE_PASSWORD": {
                      "isOptional": true,
                      "description": "ClickHouse default-user password (reference).",
                      "defaultValue": "${{clickhouse.CLICKHOUSE_PASSWORD}}"
                    },
                    "INTERNAL_API_SECRET": {
                      "isOptional": true,
                      "description": "Shared secret for internal calls (web/worker to recording-api, cymbal).",
                      "defaultValue": "{{INTERNAL_API_SECRET}}"
                    },
                    "API_QUERIES_PER_TEAM": {
                      "isOptional": true,
                      "description": "Concurrent API query limit per team (upstream hobby value).",
                      "defaultValue": "{\"1\": 100}"
                    },
                    "ENCRYPTION_SALT_KEYS": {
                      "isOptional": true,
                      "description": "Salt for encrypted fields. Generated once; never change after first deploy.",
                      "defaultValue": "{{ENCRYPTION_SALT_KEYS}}"
                    },
                    "PERSONS_DB_READER_URL": {
                      "isOptional": true,
                      "description": "Persons database reader (same Postgres database).",
                      "defaultValue": "${{Postgres.DATABASE_URL}}"
                    },
                    "PERSONS_DB_WRITER_URL": {
                      "isOptional": true,
                      "description": "Persons database (same Postgres database in the hobby layout).",
                      "defaultValue": "${{Postgres.DATABASE_URL}}"
                    },
                    "INTERNAL_REQUEST_TOKEN": {
                      "isOptional": true,
                      "description": "Token for Django to feature-flags calls (flag test evaluation).",
                      "defaultValue": "{{INTERNAL_REQUEST_TOKEN}}"
                    },
                    "OBJECT_STORAGE_ENABLED": {
                      "isOptional": true,
                      "description": "Use S3 object storage for exports and media.",
                      "defaultValue": "true"
                    },
                    "CLICKHOUSE_API_PASSWORD": {
                      "isOptional": true,
                      "description": "Password of the api user (reference).",
                      "defaultValue": "${{clickhouse.CLICKHOUSE_API_PASSWORD}}"
                    },
                    "CLICKHOUSE_APP_PASSWORD": {
                      "isOptional": true,
                      "description": "Password of the app user (reference).",
                      "defaultValue": "${{clickhouse.CLICKHOUSE_APP_PASSWORD}}"
                    },
                    "OBJECT_STORAGE_ENDPOINT": {
                      "isOptional": true,
                      "description": "SeaweedFS S3 endpoint for exports, media and AI blobs (private network).",
                      "defaultValue": "http://${{seaweedfs.RAILWAY_PRIVATE_DOMAIN}}:8333"
                    },
                    "FEATURE_FLAGS_SERVICE_URL": {
                      "isOptional": true,
                      "description": "Internal URL of the Rust feature-flags service.",
                      "defaultValue": "http://${{feature-flags.RAILWAY_PRIVATE_DOMAIN}}:3001"
                    },
                    "CLICKHOUSE_DICT_READER_USER": {
                      "isOptional": true,
                      "description": "Read-only user ClickHouse dictionaries authenticate as.",
                      "defaultValue": "dict_reader"
                    },
                    "DISABLE_SECURE_SSL_REDIRECT": {
                      "isOptional": true,
                      "description": "TLS is terminated by Railway; avoids a redirect loop.",
                      "defaultValue": "true"
                    },
                    "CLICKHOUSE_LOGS_CLUSTER_HOST": {
                      "isOptional": true,
                      "description": "ClickHouse host for the logs product (same server; upstream default is localhost).",
                      "defaultValue": "${{clickhouse.RAILWAY_PRIVATE_DOMAIN}}"
                    },
                    "OBJECT_STORAGE_ACCESS_KEY_ID": {
                      "isOptional": true,
                      "description": "Object storage access key (reference).",
                      "defaultValue": "${{seaweedfs.AWS_ACCESS_KEY_ID}}"
                    },
                    "CLICKHOUSE_LOGS_CLUSTER_SECURE": {
                      "isOptional": true,
                      "description": "Plain TCP for the logs cluster connection.",
                      "defaultValue": "false"
                    },
                    "OBJECT_STORAGE_PUBLIC_ENDPOINT": {
                      "isOptional": true,
                      "description": "Base URL for presigned downloads; the proxy forwards /posthog/* to seaweedfs.",
                      "defaultValue": "${{SITE_URL}}"
                    },
                    "CLICKHOUSE_DICT_READER_PASSWORD": {
                      "isOptional": true,
                      "description": "Password of the dict_reader user (reference).",
                      "defaultValue": "${{clickhouse.CLICKHOUSE_DICT_READER_PASSWORD}}"
                    },
                    "OBJECT_STORAGE_FORCE_PATH_STYLE": {
                      "isOptional": true,
                      "description": "SeaweedFS needs path-style requests.",
                      "defaultValue": "true"
                    },
                    "CLICKHOUSE_LOGS_CLUSTER_PASSWORD": {
                      "isOptional": true,
                      "description": "Password for the logs cluster connection (default user).",
                      "defaultValue": "${{clickhouse.CLICKHOUSE_PASSWORD}}"
                    },
                    "OBJECT_STORAGE_SECRET_ACCESS_KEY": {
                      "isOptional": true,
                      "description": "Object storage secret key (reference).",
                      "defaultValue": "${{seaweedfs.AWS_SECRET_ACCESS_KEY}}"
                    },
                    "SESSION_RECORDING_V2_S3_ENDPOINT": {
                      "isOptional": true,
                      "description": "SeaweedFS S3 endpoint for session recordings.",
                      "defaultValue": "http://${{seaweedfs.RAILWAY_PRIVATE_DOMAIN}}:8333"
                    },
                    "RAILWAY_DEPLOYMENT_DRAINING_SECONDS": {
                      "isOptional": true,
                      "description": "Let in-flight requests finish on redeploy.",
                      "defaultValue": "30"
                    },
                    "SESSION_RECORDING_V2_S3_ACCESS_KEY_ID": {
                      "isOptional": true,
                      "description": "Recording store access key (reference).",
                      "defaultValue": "${{seaweedfs.AWS_ACCESS_KEY_ID}}"
                    },
                    "SESSION_RECORDING_V2_S3_SECRET_ACCESS_KEY": {
                      "isOptional": true,
                      "description": "Recording store secret key (reference).",
                      "defaultValue": "${{seaweedfs.AWS_SECRET_ACCESS_KEY}}"
                    }
                  },
                  "networking": {
                    "tcpProxies": {},
                    "serviceDomains": {}
                  }
                }
              }
            }
          }
        }
      }
    }
  },
  "post_deploy": {
    "healthcheck": {
      "service": "proxy",
      "method": "GET",
      "path": "/_proxy/health",
      "expect_status": 200
    }
  },
  "resources": {
    "expected_services": 23,
    "needs_volume": true
  },
  "generated_at": "2026-10-11T22:14:38.939Z",
  "generator_version": "0.1.0",
  "status": "degraded",
  "validated_at": "2026-10-11T21:01:20.428Z",
  "success_rate_30d": 0,
  "validation": {
    "last_run_id": "run_c860976e5220428a8d4a",
    "checks": [
      {
        "name": "workflow_completed",
        "passed": true
      },
      {
        "name": "all_services_deployed",
        "passed": false,
        "detail": "SUCCESS,SUCCESS,SUCCESS,SUCCESS,SUCCESS,SUCCESS,SUCCESS,SUCCESS,SUCCESS,SUCCESS,SUCCESS,SUCCESS,QUEUED,SUCCESS,SUCCESS,CRASHED,QUEUED,QUEUED,SUCCESS,QUEUED,SUCCESS,SUCCESS,QUEUED"
      }
    ]
  }
}
