{
  "manifest_version": "1.0.0",
  "template": {
    "id": "1c3db373-ba96-44e6-b85b-82a377a717ed",
    "slug": "happyview-1",
    "name": "HappyView (deprecated)",
    "description": "A lexicon-driven ATProto AppView.",
    "url": "https://railway.com/deploy/happyview-1"
  },
  "status": "unvalidated",
  "validated_at": null,
  "success_rate_30d": null,
  "services": [
    {
      "name": "Postgres",
      "source": {
        "image": "ghcr.io/gamesgamesgamesgamesgames/happyview-postgres:latest"
      },
      "needs_volume": true,
      "volume_mount_path": "/var/lib/postgresql/data",
      "tcp_ports": [
        5432
      ],
      "http": false
    },
    {
      "name": "Tap",
      "source": {
        "image": "ghcr.io/gamesgamesgamesgamesgames/tap:latest"
      },
      "needs_volume": false,
      "http": false
    },
    {
      "name": "HappyView",
      "source": {
        "image": "ghcr.io/gamesgamesgamesgamesgames/happyview:1"
      },
      "needs_volume": false,
      "http": false
    },
    {
      "name": "AIP",
      "source": {
        "image": "ghcr.io/gamesgamesgamesgamesgames/aip:2.2.4-dev.2"
      },
      "needs_volume": false,
      "http": false
    }
  ],
  "required_inputs": [
    {
      "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.",
      "secret": false,
      "strategy": "default",
      "default": "railway"
    },
    {
      "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": "DATABASE_PUBLIC_URL",
      "service": "Postgres",
      "description": "Public URL to connect to Postgres database, used by the Data panel.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "RAILWAY_DEPLOYMENT_DRAINING_SECONDS",
      "service": "Postgres",
      "description": "Allow Postgres to cleanly shut down",
      "secret": false,
      "strategy": "default",
      "default": "60"
    },
    {
      "key": "TAP_DATABASE_URL",
      "service": "Tap",
      "description": "PostgreSQL connection string for the Tap database",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_private_domain"
    },
    {
      "key": "TAP_ADMIN_PASSWORD",
      "service": "Tap",
      "description": "Basic auth password required for all API requests; referenced from HappyView",
      "secret": true,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "AIP_URL",
      "service": "HappyView",
      "description": "Internal URL of the AIP service, used for auth validation and proxying OAuth requests",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_private_domain"
    },
    {
      "key": "TAP_URL",
      "service": "HappyView",
      "description": "Internal URL of the Tap service for firehose consumption and backfill",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_private_domain"
    },
    {
      "key": "RELAY_URL",
      "service": "HappyView",
      "description": "ATProto relay URL for repo discovery during backfill",
      "secret": false,
      "strategy": "default",
      "default": "https://relay1.us-east.bsky.network"
    },
    {
      "key": "DATABASE_URL",
      "service": "HappyView",
      "description": "PostgreSQL connection string for the HappyView database",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_private_domain"
    },
    {
      "key": "AIP_PUBLIC_URL",
      "service": "HappyView",
      "description": "Public URL of the AIP service, returned to the browser for OAuth redirects and DPoP proofs; falls back to AIP_URL if not set",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_domain"
    },
    {
      "key": "TAP_ADMIN_PASSWORD",
      "service": "HappyView",
      "description": "Admin password for authenticating with the Tap service API",
      "secret": true,
      "strategy": "generate",
      "generate": "strong_password"
    },
    {
      "key": "ADMIN_DIDS",
      "service": "AIP",
      "description": "Comma-separated list of DIDs with admin access to the AIP server",
      "secret": false,
      "strategy": "ask_user"
    },
    {
      "key": "DATABASE_URL",
      "service": "AIP",
      "description": "PostgreSQL connection string for the AIP database",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_private_domain"
    },
    {
      "key": "EXTERNAL_BASE",
      "service": "AIP",
      "description": "Public base URL of the AIP server, used for OAuth issuer identity and redirect validation",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_domain"
    },
    {
      "key": "DPOP_NONCE_SEED",
      "service": "AIP",
      "description": "Seed for generating DPoP nonces",
      "secret": false,
      "strategy": "generate",
      "generate": "random_base64_32"
    },
    {
      "key": "STORAGE_BACKEND",
      "service": "AIP",
      "description": "Storage backend type: memory or postgres; defaults to memory",
      "secret": false,
      "strategy": "default",
      "default": "postgres"
    },
    {
      "key": "ENABLE_CLIENT_API",
      "service": "AIP",
      "description": "Enable the dynamic client registration API; set to true to allow runtime client registration",
      "secret": false,
      "strategy": "default",
      "default": "true"
    },
    {
      "key": "OAUTH_SIGNING_KEYS",
      "service": "AIP",
      "description": "Private keys for signing OAuth tokens (base58-encoded); see the [AIP docs](https://github.com/graze-social/aip/blob/main/CONFIGURATION.md#key-generation) for details",
      "secret": true,
      "strategy": "generate",
      "generate": "random_base64_32"
    },
    {
      "key": "ATPROTO_OAUTH_SIGNING_KEYS",
      "service": "AIP",
      "description": "Private keys for signing ATProto-specific OAuth tokens (base58-encoded); see the [AIP docs](https://github.com/graze-social/aip/blob/main/CONFIGURATION.md#key-generation) for details",
      "secret": true,
      "strategy": "generate",
      "generate": "random_base64_32"
    }
  ],
  "deploy": {
    "mcp": {
      "server": "railway",
      "tool": "deploy_template",
      "args": {
        "template_code": "happyview-1"
      }
    },
    "cli": "railway deploy --template happyview-1",
    "api": {
      "method": "POST",
      "path": "/graphql/v2",
      "body": {
        "query": "mutation templateDeploy($input: TemplateDeployV2Input!) { templateDeployV2(input: $input) { projectId workflowId } }",
        "variables": {
          "input": {
            "templateId": "1c3db373-ba96-44e6-b85b-82a377a717ed",
            "serializedConfig": {
              "services": {
                "09a4401e-4ff0-4a78-8ec5-a617e9ca0d84": {
                  "icon": "https://devicons.railway.app/i/postgresql.svg",
                  "name": "Postgres",
                  "build": {},
                  "deploy": {
                    "requiredMountPath": "/var/lib/postgresql/data"
                  },
                  "source": {
                    "image": "ghcr.io/gamesgamesgamesgamesgames/happyview-postgres:latest"
                  },
                  "variables": {
                    "PGDATA": {
                      "isOptional": false,
                      "description": "Location where the database will be initialized",
                      "defaultValue": "/var/lib/postgresql/data/pgdata"
                    },
                    "PGHOST": {
                      "isOptional": false,
                      "description": "Railway Private Domain Name.",
                      "defaultValue": "${{RAILWAY_PRIVATE_DOMAIN}}"
                    },
                    "PGPORT": {
                      "isOptional": false,
                      "description": "Port to connect to Postgres.",
                      "defaultValue": "5432"
                    },
                    "PGUSER": {
                      "isOptional": false,
                      "description": "Required variable for Data panel",
                      "defaultValue": "${{ POSTGRES_USER }}"
                    },
                    "PGDATABASE": {
                      "isOptional": false,
                      "description": "Required variable for the data panel.",
                      "defaultValue": "${{POSTGRES_DB}}"
                    },
                    "PGPASSWORD": {
                      "isOptional": false,
                      "description": "Required variable for Data panel",
                      "defaultValue": "${{POSTGRES_PASSWORD}}"
                    },
                    "POSTGRES_DB": {
                      "isOptional": false,
                      "description": "Default database created when image is started.",
                      "defaultValue": "railway"
                    },
                    "DATABASE_URL": {
                      "isOptional": false,
                      "description": "URL to connect to Postgres database.",
                      "defaultValue": "postgresql://${{PGUSER}}:${{POSTGRES_PASSWORD}}@${{RAILWAY_PRIVATE_DOMAIN}}:5432/${{PGDATABASE}}"
                    },
                    "POSTGRES_USER": {
                      "isOptional": false,
                      "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": false,
                      "description": "Password to connect to DB",
                      "defaultValue": "{{POSTGRES_PASSWORD}}"
                    },
                    "DATABASE_PUBLIC_URL": {
                      "description": "Public URL to connect to Postgres database, used by the Data panel.",
                      "defaultValue": "postgresql://${{PGUSER}}:${{POSTGRES_PASSWORD}}@${{RAILWAY_TCP_PROXY_DOMAIN}}:${{RAILWAY_TCP_PROXY_PORT}}/${{PGDATABASE}}"
                    },
                    "RAILWAY_DEPLOYMENT_DRAINING_SECONDS": {
                      "isOptional": false,
                      "description": "Allow Postgres to cleanly shut down",
                      "defaultValue": "60"
                    }
                  },
                  "networking": {
                    "tcpProxies": {
                      "5432": {}
                    },
                    "serviceDomains": {}
                  },
                  "volumeMounts": {
                    "09a4401e-4ff0-4a78-8ec5-a617e9ca0d84": {
                      "mountPath": "/var/lib/postgresql/data"
                    }
                  }
                },
                "15644181-0ac9-41de-bb2a-f2f44a35e24a": {
                  "icon": "https://freepnglogo.com/images/all_img/bluesky-logo-495a.png",
                  "name": "Tap",
                  "source": {
                    "image": "ghcr.io/gamesgamesgamesgamesgames/tap:latest"
                  },
                  "variables": {
                    "TAP_DATABASE_URL": {
                      "description": "PostgreSQL connection string for the Tap database",
                      "defaultValue": "postgresql://${{Postgres.POSTGRES_USER}}:${{Postgres.POSTGRES_PASSWORD}}@${{Postgres.RAILWAY_PRIVATE_DOMAIN}}:${{Postgres.PGPORT}}/tap"
                    },
                    "TAP_ADMIN_PASSWORD": {
                      "description": "Basic auth password required for all API requests; referenced from HappyView",
                      "defaultValue": "${{HappyView.TAP_ADMIN_PASSWORD}}"
                    }
                  }
                },
                "5e275b62-287a-4480-826f-2df4ea1ab7c5": {
                  "icon": "https://raw.githubusercontent.com/gamesgamesgamesgamesgames/happyview/main/design/face.png",
                  "name": "HappyView",
                  "source": {
                    "image": "ghcr.io/gamesgamesgamesgamesgames/happyview:1"
                  },
                  "variables": {
                    "AIP_URL": {
                      "description": "Internal URL of the AIP service, used for auth validation and proxying OAuth requests",
                      "defaultValue": "http://${{AIP.RAILWAY_PRIVATE_DOMAIN}}:8080"
                    },
                    "TAP_URL": {
                      "description": "Internal URL of the Tap service for firehose consumption and backfill",
                      "defaultValue": "http://${{Tap.RAILWAY_PRIVATE_DOMAIN}}:2480"
                    },
                    "RELAY_URL": {
                      "description": "ATProto relay URL for repo discovery during backfill",
                      "defaultValue": "https://relay1.us-east.bsky.network"
                    },
                    "DATABASE_URL": {
                      "description": "PostgreSQL connection string for the HappyView database",
                      "defaultValue": "postgresql://${{Postgres.POSTGRES_USER}}:${{Postgres.POSTGRES_PASSWORD}}@${{Postgres.RAILWAY_PRIVATE_DOMAIN}}:${{Postgres.PGPORT}}/happyview"
                    },
                    "AIP_PUBLIC_URL": {
                      "description": "Public URL of the AIP service, returned to the browser for OAuth redirects and DPoP proofs; falls back to AIP_URL if not set",
                      "defaultValue": "https://${{AIP.RAILWAY_PUBLIC_DOMAIN}}"
                    },
                    "TAP_ADMIN_PASSWORD": {
                      "description": "Admin password for authenticating with the Tap service API",
                      "defaultValue": "{{TAP_ADMIN_PASSWORD}}"
                    }
                  }
                },
                "e6e1bae1-bdfa-4838-bd1b-78e7ba74caa4": {
                  "icon": "https://github.com/gamesgamesgamesgamesgames/aip/raw/main/aip.png",
                  "name": "AIP",
                  "source": {
                    "image": "ghcr.io/gamesgamesgamesgamesgames/aip:2.2.4-dev.2"
                  },
                  "variables": {
                    "ADMIN_DIDS": {
                      "description": "Comma-separated list of DIDs with admin access to the AIP server",
                      "defaultValue": "{{ADMIN_DIDS}}"
                    },
                    "DATABASE_URL": {
                      "isOptional": false,
                      "description": "PostgreSQL connection string for the AIP database",
                      "defaultValue": "postgresql://${{Postgres.POSTGRES_USER}}:${{Postgres.POSTGRES_PASSWORD}}@${{Postgres.RAILWAY_PRIVATE_DOMAIN}}:${{Postgres.PGPORT}}/aip"
                    },
                    "EXTERNAL_BASE": {
                      "description": "Public base URL of the AIP server, used for OAuth issuer identity and redirect validation",
                      "defaultValue": "https://${{RAILWAY_PUBLIC_DOMAIN}}"
                    },
                    "DPOP_NONCE_SEED": {
                      "description": "Seed for generating DPoP nonces",
                      "defaultValue": "{{DPOP_NONCE_SEED}}"
                    },
                    "STORAGE_BACKEND": {
                      "isOptional": true,
                      "description": "Storage backend type: memory or postgres; defaults to memory",
                      "defaultValue": "postgres"
                    },
                    "ENABLE_CLIENT_API": {
                      "description": "Enable the dynamic client registration API; set to true to allow runtime client registration",
                      "defaultValue": "true"
                    },
                    "OAUTH_SIGNING_KEYS": {
                      "description": "Private keys for signing OAuth tokens (base58-encoded); see the [AIP docs](https://github.com/graze-social/aip/blob/main/CONFIGURATION.md#key-generation) for details",
                      "defaultValue": "{{OAUTH_SIGNING_KEYS}}"
                    },
                    "ATPROTO_OAUTH_SIGNING_KEYS": {
                      "description": "Private keys for signing ATProto-specific OAuth tokens (base58-encoded); see the [AIP docs](https://github.com/graze-social/aip/blob/main/CONFIGURATION.md#key-generation) for details",
                      "defaultValue": "{{ATPROTO_OAUTH_SIGNING_KEYS}}"
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  },
  "post_deploy": {},
  "resources": {
    "expected_services": 4,
    "needs_volume": true
  },
  "generated_at": "2026-09-21T16:15:12.787Z",
  "generator_version": "0.1.0"
}
