Files
mesh-catalog/modules/umami/module.json
T
jschoubben d301e05794 fix: postgres consumers connect to the db the mesh named (the login), not a hardcoded app name
The postgres provisioner creates each consumer a database named after the login the mesh
minted (mesh_<node>_<module>), per ADR 0048 -- 'a same-named database under exactly that
login'. But baserow, letta, umami, gitea, keycloak and nextcloud each hardcoded their app db
name (DATABASE_NAME=baserow, /letta, /umami, NAME=gitea, /keycloak, POSTGRES_DB=nextcloud),
so the service connected to a database that does not exist ('database letta does not exist').
Each now uses ${bound:postgres-database:as} as the db name -- the login, which is also the db
name -- matching the working meshboard pattern and the provisioner's actual behaviour.

Found by the two-node DB-consumer lab install (mesh-lab assigned-two-node-db); baserow is
proven connecting and running there. The S3 bucket name is the same class of assumption and is
a separate follow-up (s3 identity has its own length bound).

Claude-Session: https://claude.ai/code/session_01LrgweAeERJYBg88c5cKDzF
2026-09-06 13:47:16 +02:00

121 lines
3.1 KiB
JSON

{
"module": "umami",
"version": "1",
"capabilities": [
"container-runtime"
],
"requires": [
"postgres-database"
],
"contributes": {
"postgres-database": {
"name": "umami"
}
},
"binds": {
"postgres-database": "/var/lib/umami/database.json"
},
"secrets": {
"postgres-database": "/var/lib/umami/database.secret"
},
"provides": [
{
"name": "analytics",
"scope": "mesh"
}
],
"serves": {
"analytics": {}
},
"receives": {
"analytics": "/var/lib/umami/grants/mesh.json"
},
"grants": {
"analytics": "/var/lib/umami/grants"
},
"own-secrets": {
"app-secret": "/var/lib/umami/app.secret",
"admin": "/var/lib/umami/admin.secret",
"broker": "/var/lib/mesh/umami/broker"
},
"listens": [
{
"port": 3000,
"protocol": "tcp",
"from": "anywhere",
"why": "one port serves two surfaces: the dashboard (the proxy gates it to the mesh) and the public collection endpoint that the browsers of every tracked site POST to — so the port itself must be reachable from anywhere"
}
],
"resources": [
{
"id": "mesh-state",
"type": "directory",
"path": "/var/lib/mesh/umami",
"mode": "0700"
},
{
"id": "state",
"type": "directory",
"path": "/var/lib/umami",
"mode": "0700"
},
{
"id": "grants",
"type": "directory",
"path": "/var/lib/umami/grants",
"mode": "0700"
},
{
"id": "server-env",
"type": "file",
"path": "/var/lib/umami/server.env",
"mode": "0600",
"content": "DATABASE_URL=postgresql://${bound:postgres-database:as}:${secret:postgres-database}@${bound:postgres-database:at}:${bound:postgres-database:port}/${bound:postgres-database:as}\nDATABASE_TYPE=postgresql\nAPP_SECRET=${secret:app-secret}\n"
},
{
"id": "provisioner-env",
"type": "file",
"path": "/var/lib/umami/provisioner.env",
"mode": "0600",
"content": "MESH_PROVISION_UMAMI_URL=http://umami:3000\nGRANTS=/var/lib/umami/grants\n"
},
{
"id": "net",
"type": "network",
"name": "umami"
},
{
"id": "server",
"type": "container",
"name": "umami",
"image": "ghcr.io/umami-software/umami@sha256:fa32d116cf20cad52cbc3fad9a63b46e7fa02299d8f967168eb453d49c476b4a",
"network": "umami",
"env-file": [
"/var/lib/umami/server.env"
],
"ports": [
"3000"
]
},
{
"id": "runtime",
"type": "container",
"name": "mesh-umami",
"image": "mesh-runtime-umami@sha256:0000000000000000000000000000000000000000000000000000000000000000",
"network": "umami",
"volumes": [
"/var/lib/mesh/umami/broker:/run/secrets/broker:ro",
"/var/lib/umami/grants:/var/lib/umami/grants",
"/var/lib/umami/admin.secret:/run/secrets/admin:ro"
],
"env": {
"MESH_BROKER_FILE": "/run/secrets/broker",
"MESH_RECEIVES": "/var/lib/umami/grants/mesh.json"
},
"env-file": [
"/var/lib/umami/provisioner.env"
]
}
]
}