Files
mesh-catalog/modules/supabase/module.json
T

652 lines
19 KiB
JSON

{
"module": "supabase",
"version": "1",
"capabilities": [
"container-runtime"
],
"listens": [
{
"name": "api",
"port": 8000,
"protocol": "tcp",
"from": "mesh",
"why": "the Kong gateway: the REST, auth, storage, realtime, functions and GraphQL APIs under their /\u2026/v1 paths, and Studio at / behind the dashboard password. The one surface people and apps use, reached through the route"
},
{
"name": "pooler-session",
"port": 5432,
"protocol": "tcp",
"from": "mesh",
"why": "Supavisor's session-mode Postgres port, for clients that connect to the database directly as <user>.<tenant>"
},
{
"name": "pooler-transaction",
"port": 6543,
"protocol": "tcp",
"from": "mesh",
"why": "Supavisor's transaction-mode Postgres port"
}
],
"requires": [
"route"
],
"own-secrets": {
"postgres": "${dir:state}/postgres.secret",
"jwt": "${dir:state}/jwt.secret",
"anon-key": "${dir:state}/anon-key.secret",
"service-role-key": "${dir:state}/service-role-key.secret",
"dashboard-user": "${dir:state}/dashboard-user.secret",
"dashboard": "${dir:state}/dashboard.secret",
"logflare": {
"path": "${dir:state}/logflare.secret",
"taken": "at-start"
},
"pooler-vault": "${dir:state}/pooler-vault.secret",
"key-base-a": "${dir:state}/key-base-a.secret",
"key-base-b": "${dir:state}/key-base-b.secret",
"openai": {
"path": "${dir:state}/openai.secret",
"issued-by": "outside"
}
},
"contributes": {
"route": {
"label": "supabase",
"endpoint": "api"
}
},
"binds": {
"route": "${dir:state}/route.json"
},
"data": {
"own": [
{
"id": "db",
"path": "${dir:db-data}",
"class": "valuable",
"backup": {
"dump": "docker exec supabase-db pg_dumpall -h 127.0.0.1 -U supabase_admin > ${dir:dumps}/all.sql.partial && mv ${dir:dumps}/all.sql.partial ${dir:dumps}/all.sql",
"into": "dumps"
},
"why": "every table; copied by pg_dumpall inside the database's container (local connections are trusted there), since a running store's files are not a consistent copy"
},
{
"id": "dumps",
"path": "${dir:dumps}",
"class": "rebuildable",
"why": "last night's dump of the database, made again every night"
},
{
"id": "storage",
"path": "${dir:storage}",
"class": "valuable",
"why": "uploaded objects"
},
{
"id": "functions",
"path": "${dir:functions}",
"class": "valuable",
"why": "the edge functions' code"
},
{
"id": "db-config",
"path": "${dir:db-config}",
"class": "rebuildable",
"why": "the database's configuration, seeded again"
}
]
},
"config": {
"pooler": {
"type": "object",
"description": "The connection pooler's settings, laid over the file's: its tenant, pool size and the most client connections it takes.",
"trusted": true,
"default": {
"tenant": "default",
"pool-size": 20,
"max-client-connections": 100
}
}
},
"resources": [
{
"id": "state",
"type": "directory",
"mode": "0700",
"place": "."
},
{
"id": "db-init",
"type": "directory",
"path": "${dir:state}/db-init",
"mode": "0755"
},
{
"id": "functions-main-dir",
"type": "directory",
"path": "${dir:state}/functions-main",
"mode": "0755"
},
{
"id": "db-data",
"type": "directory",
"mode": "0700",
"owner": "105:106"
},
{
"id": "dumps",
"type": "directory",
"path": "${dir:state}/dumps",
"mode": "0700"
},
{
"id": "db-config",
"type": "directory",
"mode": "0755",
"owner": "105:106"
},
{
"id": "storage",
"type": "directory",
"mode": "0755"
},
{
"id": "functions",
"type": "directory",
"mode": "0755"
},
{
"id": "settings",
"type": "file",
"path": "${dir:state}/settings.json",
"mode": "0644",
"merge": "json",
"takes-config": ["pooler"],
"template": "files/settings.json"
},
{
"id": "kong-conf",
"type": "file",
"path": "${dir:state}/kong.yml",
"mode": "0600",
"owner": "100:65533",
"template": "files/kong.yml"
},
{
"id": "auth-conf",
"type": "file",
"path": "${dir:state}/gotrue.env",
"mode": "0600",
"owner": "1000:1000",
"template": "files/gotrue.env"
},
{
"id": "rest-conf",
"type": "file",
"path": "${dir:state}/postgrest.conf",
"mode": "0600",
"owner": "1000:1000",
"template": "files/postgrest.conf"
},
{
"id": "vector-conf",
"type": "file",
"path": "${dir:state}/vector.yml",
"mode": "0600",
"template": "files/vector.yml"
},
{
"id": "pooler-conf",
"type": "file",
"path": "${dir:state}/pooler.exs",
"mode": "0644",
"template": "files/pooler.exs"
},
{
"id": "db-init-roles",
"type": "file",
"path": "${dir:state}/db-init/roles.sql",
"mode": "0600",
"owner": "105:106",
"template": "files/db-init/roles.sql"
},
{
"id": "db-init-jwt",
"type": "file",
"path": "${dir:state}/db-init/jwt.sql",
"mode": "0600",
"owner": "105:106",
"template": "files/db-init/jwt.sql"
},
{
"id": "db-init-realtime",
"type": "file",
"path": "${dir:state}/db-init/realtime.sql",
"mode": "0600",
"owner": "105:106",
"template": "files/db-init/realtime.sql"
},
{
"id": "db-init-supabase",
"type": "file",
"path": "${dir:state}/db-init/supabase.sql",
"mode": "0600",
"owner": "105:106",
"template": "files/db-init/supabase.sql"
},
{
"id": "db-init-logs",
"type": "file",
"path": "${dir:state}/db-init/logs.sql",
"mode": "0600",
"owner": "105:106",
"template": "files/db-init/logs.sql"
},
{
"id": "db-init-pooler",
"type": "file",
"path": "${dir:state}/db-init/pooler.sql",
"mode": "0600",
"owner": "105:106",
"template": "files/db-init/pooler.sql"
},
{
"id": "db-init-webhooks",
"type": "file",
"path": "${dir:state}/db-init/webhooks.sql",
"mode": "0600",
"owner": "105:106",
"template": "files/db-init/webhooks.sql"
},
{
"id": "functions-main",
"type": "file",
"path": "${dir:state}/functions-main/index.ts",
"mode": "0644",
"template": "files/functions-main/index.ts"
},
{
"id": "realtime-env",
"type": "file",
"path": "${dir:state}/realtime-env.env",
"mode": "0600",
"template": "files/realtime-env.env"
},
{
"id": "storage-env",
"type": "file",
"path": "${dir:state}/storage-env.env",
"mode": "0600",
"template": "files/storage-env.env"
},
{
"id": "meta-env",
"type": "file",
"path": "${dir:state}/meta-env.env",
"mode": "0600",
"template": "files/meta-env.env"
},
{
"id": "functions-env",
"type": "file",
"path": "${dir:state}/functions-env.env",
"mode": "0600",
"template": "files/functions-env.env"
},
{
"id": "analytics-env",
"type": "file",
"path": "${dir:state}/analytics-env.env",
"mode": "0600",
"template": "files/analytics-env.env"
},
{
"id": "analytics-start",
"type": "file",
"path": "${dir:state}/analytics-start.sh",
"mode": "0644",
"template": "files/analytics-start.sh"
},
{
"id": "analytics-reconcile",
"type": "file",
"path": "${dir:state}/analytics-reconcile.exs",
"mode": "0644",
"template": "files/analytics-reconcile.exs"
},
{
"id": "studio-env",
"type": "file",
"path": "${dir:state}/studio-env.env",
"mode": "0600",
"template": "files/studio-env.env"
},
{
"id": "pooler-env",
"type": "file",
"path": "${dir:state}/pooler-env.env",
"mode": "0600",
"template": "files/pooler-env.env"
},
{
"id": "net",
"type": "network",
"name": "supabase"
},
{
"id": "vector",
"type": "container",
"name": "supabase-vector",
"image": "timberio/vector@sha256:4bc04aca94a44f04b427a490f346e7397ef7ce61fe589d718f744f7d92cb5c80",
"network": "supabase",
"args": [
"--config",
"/etc/vector/vector.yml"
],
"volumes": [
"${dir:state}/vector.yml:/etc/vector/vector.yml:ro",
"/var/run/docker.sock:/var/run/docker.sock:ro"
],
"restart-on": [
"vector-conf"
]
},
{
"id": "db-config-seed",
"type": "container",
"name": "supabase-db-config-seed",
"image": "supabase/postgres@sha256:ee29d0aaff03d0e12c7aa63437cba25f24246872f0ed3f82a9fd13184d780777",
"network": "supabase",
"run-once": true,
"args": [
"sh",
"-c",
"cp -rn /etc/postgresql-custom/. /seed/ && chown -R postgres:postgres /seed"
],
"volumes": [
"${dir:db-config}:/seed"
]
},
{
"id": "db",
"type": "container",
"name": "supabase-db",
"image": "supabase/postgres@sha256:ee29d0aaff03d0e12c7aa63437cba25f24246872f0ed3f82a9fd13184d780777",
"health": {
"kind": "runtime"
},
"network": "supabase",
"args": [
"postgres",
"-c",
"config_file=/etc/postgresql/postgresql.conf",
"-c",
"log_min_messages=fatal"
],
"env": {
"POSTGRES_HOST": "/var/run/postgresql",
"PGPORT": "5432",
"POSTGRES_PORT": "5432",
"PGDATABASE": "postgres",
"POSTGRES_DB": "postgres",
"POSTGRES_PASSWORD_FILE": "/run/secrets/postgres"
},
"volumes": [
"${dir:state}/postgres.secret:/run/secrets/postgres:ro",
"${dir:state}/db-init/realtime.sql:/docker-entrypoint-initdb.d/migrations/99-realtime.sql:ro",
"${dir:state}/db-init/webhooks.sql:/docker-entrypoint-initdb.d/init-scripts/98-webhooks.sql:ro",
"${dir:state}/db-init/roles.sql:/docker-entrypoint-initdb.d/init-scripts/99-roles.sql:ro",
"${dir:state}/db-init/jwt.sql:/docker-entrypoint-initdb.d/init-scripts/99-jwt.sql:ro",
"${dir:state}/db-init/supabase.sql:/docker-entrypoint-initdb.d/migrations/97-_supabase.sql:ro",
"${dir:state}/db-init/logs.sql:/docker-entrypoint-initdb.d/migrations/99-logs.sql:ro",
"${dir:state}/db-init/pooler.sql:/docker-entrypoint-initdb.d/migrations/99-pooler.sql:ro",
"${dir:db-data}:/var/lib/postgresql/data",
"${dir:db-config}:/etc/postgresql-custom"
]
},
{
"id": "db-ready",
"type": "container",
"name": "supabase-db-ready",
"image": "supabase/postgres@sha256:ee29d0aaff03d0e12c7aa63437cba25f24246872f0ed3f82a9fd13184d780777",
"network": "supabase",
"run-once": true,
"args": [
"sh",
"-c",
"for i in $(seq 150); do pg_isready -h supabase-db -p 5432 -U postgres && exit 0; sleep 2; done; echo 'the database did not come up' >&2; exit 1"
]
},
{
"id": "analytics",
"type": "container",
"name": "supabase-analytics",
"image": "supabase/logflare@sha256:e693c787ffe1ae17b6e4e920a3cdd212416d3e1f97e1bd7cb5b67de0abbb0264",
"network": "supabase",
"env-file": [
"${dir:state}/analytics-env.env"
],
"volumes": [
"${dir:state}/analytics-start.sh:/run/logflare/start.sh:ro",
"${dir:state}/vector.yml:/run/logflare/vector.yml:ro",
"${dir:state}/analytics-reconcile.exs:/run/logflare/reconcile.exs:ro"
],
"args": [
"sh",
"/run/logflare/start.sh"
],
"restart-on": [
"analytics-env",
"analytics-start",
"analytics-reconcile",
"vector-conf"
],
"secrets-in-environment": "Logflare reads its database password and API key from the environment only. The API key is never in a URL the mesh writes: logflare prints a failed request's URL, so vector sends the key in the x-api-key header, and the start script refuses to start logflare while vector.yml says otherwise"
},
{
"id": "analytics-ready",
"type": "container",
"name": "supabase-analytics-ready",
"image": "supabase/logflare@sha256:e693c787ffe1ae17b6e4e920a3cdd212416d3e1f97e1bd7cb5b67de0abbb0264",
"network": "supabase",
"run-once": true,
"args": [
"sh",
"-c",
"for i in $(seq 150); do curl -fsS -o /dev/null http://supabase-analytics:4000/health && exit 0; sleep 2; done; echo 'analytics did not come up' >&2; exit 1"
]
},
{
"id": "kong",
"type": "container",
"name": "supabase-kong",
"image": "kong@sha256:1b53405d8680a09d6f44494b7990bf7da2ea43f84a258c59717d4539abf09f6d",
"health": {
"kind": "runtime"
},
"network": "supabase",
"ports": [
"8000"
],
"env": {
"KONG_DATABASE": "off",
"KONG_DECLARATIVE_CONFIG": "/home/kong/kong.yml",
"KONG_DNS_ORDER": "LAST,A,CNAME",
"KONG_PLUGINS": "request-transformer,cors,key-auth,acl,basic-auth",
"KONG_NGINX_PROXY_PROXY_BUFFER_SIZE": "160k",
"KONG_NGINX_PROXY_PROXY_BUFFERS": "64 160k"
},
"volumes": [
"${dir:state}/kong.yml:/home/kong/kong.yml:ro"
],
"restart-on": [
"kong-conf"
]
},
{
"id": "auth",
"type": "container",
"name": "supabase-auth",
"image": "supabase/gotrue@sha256:f8b871f46f3f9c5306af00d2fb856fb5479db730bb6d4fd2757b2da8abe953f9",
"network": "supabase",
"args": [
"auth",
"-c",
"/etc/gotrue/gotrue.env"
],
"volumes": [
"${dir:state}/gotrue.env:/etc/gotrue/gotrue.env:ro"
],
"restart-on": [
"auth-conf"
]
},
{
"id": "rest",
"type": "container",
"name": "supabase-rest",
"image": "postgrest/postgrest@sha256:2cf1efd2c9c2e7606610c113cc73e936d8ce9ba089271cb9cbf11aa564bc30c7",
"network": "supabase",
"args": [
"postgrest",
"/etc/postgrest/postgrest.conf"
],
"volumes": [
"${dir:state}/postgrest.conf:/etc/postgrest/postgrest.conf:ro"
],
"restart-on": [
"rest-conf"
]
},
{
"id": "realtime",
"type": "container",
"name": "realtime-dev.supabase-realtime",
"image": "supabase/realtime@sha256:104fe2e4e09a7c81eebe0c39e3a9b9dca4684f55470ca01cb3c080d1d56453a1",
"network": "supabase",
"env-file": [
"${dir:state}/realtime-env.env"
],
"secrets-in-environment": "Supabase Realtime (Elixir release) reads DB_PASSWORD, API_JWT_SECRET and SECRET_KEY_BASE from its environment only; no file or _FILE form"
},
{
"id": "imgproxy",
"type": "container",
"name": "supabase-imgproxy",
"image": "darthsim/imgproxy@sha256:0facd355d50f3be665ebe674486f2b2e9cdaebd3f74404acd9b7fece2f661435",
"network": "supabase",
"env": {
"IMGPROXY_BIND": ":5001",
"IMGPROXY_LOCAL_FILESYSTEM_ROOT": "/",
"IMGPROXY_USE_ETAG": "true",
"IMGPROXY_ENABLE_WEBP_DETECTION": "true"
},
"volumes": [
"${dir:storage}:/var/lib/storage"
]
},
{
"id": "storage-api",
"type": "container",
"name": "supabase-storage",
"image": "supabase/storage-api@sha256:1e85dad48e8b3e85890a555e5114dc7ee48c2e8be4cfd97dd4e3564b4f104fcd",
"network": "supabase",
"volumes": [
"${dir:storage}:/var/lib/storage"
],
"env-file": [
"${dir:state}/storage-env.env"
],
"secrets-in-environment": "Supabase Storage reads its keys and DATABASE_URL from the environment only"
},
{
"id": "meta",
"type": "container",
"name": "supabase-meta",
"image": "supabase/postgres-meta@sha256:d0a96973e9f1b6303f7500421a459af3d7273b3f9f1db38610899f9f573da7c7",
"health": {
"kind": "runtime"
},
"network": "supabase",
"env-file": [
"${dir:state}/meta-env.env"
],
"secrets-in-environment": "postgres-meta reads PG_META_DB_PASSWORD from the environment only"
},
{
"id": "edge-functions",
"type": "container",
"name": "supabase-edge-functions",
"image": "supabase/edge-runtime@sha256:6f7ac3b363f6b278ff9235672a81504ad07709a07f62c50cd4fffb6708842ff1",
"network": "supabase",
"args": [
"start",
"--main-service",
"/home/deno/main"
],
"volumes": [
"${dir:functions}:/home/deno/functions",
"${dir:state}/functions-main/index.ts:/home/deno/main/index.ts:ro"
],
"env-file": [
"${dir:state}/functions-env.env"
],
"secrets-in-environment": "the edge runtime's main service hands its own environment (JWT secret, service key, database URL) to every function worker by design; there is no other channel"
},
{
"id": "studio",
"type": "container",
"name": "supabase-studio",
"image": "supabase/studio@sha256:ebf492ba82db1fc9497f56e4cdebf5cddb464b61f6227e21c8f5f3693f9dbbc5",
"health": {
"kind": "runtime"
},
"network": "supabase",
"env-file": [
"${dir:state}/studio-env.env"
],
"restart-on": [
"studio-env"
],
"secrets-in-environment": "Studio (Next.js) reads its keys, the database password and the OpenAI key from the environment only"
},
{
"id": "pooler",
"type": "container",
"name": "supabase-pooler",
"image": "supabase/supavisor@sha256:2f24ab556380db7aaf402d2ec5db09d1974739e685781a91a77ab5ae0dadb3a5",
"network": "supabase",
"ports": [
"5432",
"6543"
],
"args": [
"/bin/sh",
"-c",
"/app/bin/migrate && /app/bin/supavisor eval \"$(cat /etc/pooler/pooler.exs)\" && /app/bin/server"
],
"volumes": [
"${dir:state}/pooler.exs:/etc/pooler/pooler.exs:ro",
"${dir:state}/settings.json:/etc/pooler/settings.json:ro"
],
"restart-on": [
"pooler-conf",
"settings"
],
"env-file": [
"${dir:state}/pooler-env.env"
],
"secrets-in-environment": "Supavisor reads DATABASE_URL, SECRET_KEY_BASE, VAULT_ENC_KEY and the JWT secret from the environment only"
}
],
"build": {
"artifacts": [
{
"name": "files",
"kind": "archive",
"from": "files"
}
]
}
}