app/matrix: initial matrix test deployment WIP
diff --git a/app/matrix/prod.jsonnet b/app/matrix/prod.jsonnet
new file mode 100644
index 0000000..81b69f0
--- /dev/null
+++ b/app/matrix/prod.jsonnet
@@ -0,0 +1,208 @@
+# matrix.hackerspace.pl, a matrix/synapse instance
+# This needs a secret provisioned, create with:
+#    kubectl -n matrix create secret generic synapse --from-literal=postgres_password=$(pwgen 24 1)
+
+local kube = import "../../kube/kube.libsonnet";
+local postgres = import "../../kube/postgres.libsonnet";
+
+{
+    local app = self,
+    local cfg = app.cfg,
+    cfg:: {
+        namespace: "matrix",
+        image: "matrixdotorg/synapse:v0.99.3.2",
+        riotImage: "bubuntux/riot-web:v1.1.0",
+        domain: "matrix.hackerspace.pl",
+        serverName: "hackerspace.pl",
+        storageClassName: "waw-hdd-redundant-1",
+    },
+
+    metadata(component):: {
+        namespace: app.cfg.namespace,
+        labels: {
+            "app.kubernetes.io/name": "matrix",
+            "app.kubernetes.io/managed-by": "kubecfg",
+            "app.kubernetes.io/component": component,
+        },
+    },
+
+    namespace: kube.Namespace(app.cfg.namespace),
+
+    postgres: postgres {
+        cfg+: {
+            namespace: cfg.namespace,
+            appName: "synapse",
+            database: "synapse",
+            username: "synapse",
+            password: { secretKeyRef: { name: "synapse", key: "postgres_password" } },
+        },
+    },
+
+    dataVolume: kube.PersistentVolumeClaim("synapse-data") {
+        metadata+: app.metadata("synapse-data"),
+        spec+: {
+            storageClassName: cfg.storageClassName,
+            accessModes: [ "ReadWriteOnce" ],
+            resources: {
+                requests: {
+                    storage: "50Gi",
+                },
+            },
+        },
+    },
+    deployment: kube.Deployment("synapse") {
+        metadata+: app.metadata("synapse"),
+        spec+: {
+            replicas: 1,
+            template+: {
+                spec+: {
+                    volumes_: {
+                        data: kube.PersistentVolumeClaimVolume(app.dataVolume),
+                    },
+                    containers_: {
+                        web: kube.Container("synapse") {
+                            image: cfg.image,
+                            ports_: {
+                                http: { containerPort: 8008 },
+                            },
+                            env_: {
+                                SYNAPSE_SERVER_NAME: app.cfg.serverName,
+                                SYNAPSE_REPORT_STATS: "no",
+                                SYNAPSE_NO_TLS: "1",
+
+                                POSTGRES_HOST: "postgres",
+                                POSTGRES_USER: app.postgres.cfg.username,
+                                POSTGRES_PORT: "5432",
+                                POSTGRES_DB: app.postgres.cfg.database,
+                                POSTGRES_PASSWORD: { secretKeyRef: { name: "synapse", key: "postgres_password" } },
+                            },
+                            volumeMounts_: {
+                                data: { mountPath: "/data" },
+                            },
+                        },
+                    },
+                },
+            },
+        },
+    },
+
+    riotConfig: kube.ConfigMap("riot-web-config") {
+        metadata+: app.metadata("riot-web-config"),
+        data: {
+            "config.json": std.manifestJsonEx({
+                "default_hs_url": "https://matrix.hackerspace.pl",
+                "default_is_url": "https://vector.im",
+                "disable_custom_urls": false,
+                "disable_guests": false,
+                "disable_login_language_selector": false,
+                "disable_3pid_login": false,
+                "brand": "Riot",
+                "integrations_ui_url": "https://scalar.vector.im/",
+                "integrations_rest_url": "https://scalar.vector.im/api",
+                "integrations_jitsi_widget_url": "https://scalar.vector.im/api/widgets/jitsi.html",
+                "bug_report_endpoint_url": "https://riot.im/bugreports/submit",
+                "features": {
+                    "feature_groups": "labs",
+                    "feature_pinning": "labs",
+                    "feature_reactions": "labs"
+                },
+                "default_federate": true,
+                "default_theme": "light",
+                "roomDirectory": {
+                    "servers": [
+                        "matrix.hackerspace.pl"
+                    ]
+                },
+                "welcomeUserId": "@riot-bot:matrix.org",
+                "piwik": {
+                    "url": "https://piwik.riot.im/",
+                    "whitelistedHSUrls": ["https://matrix.org"],
+                    "whitelistedISUrls": ["https://vector.im", "https://matrix.org"],
+                    "siteId": 1
+                },
+                "enable_presence_by_hs_url": {
+                    "https://matrix.org": false
+                }
+            }, ""),
+        },
+    },
+
+    riotDeployment: kube.Deployment("riot-web") {
+        metadata+: app.metadata("riot-web"),
+        spec+: {
+            replicas: 1,
+            template+: {
+                spec+: {
+                    volumes_: {
+                        config: kube.ConfigMapVolume(app.riotConfig),
+                    },
+                    containers_: {
+                        web: kube.Container("synapse") {
+                            image: cfg.riotImage,
+                            ports_: {
+                                http: { containerPort: 80 },
+                            },
+                            volumeMounts_: {
+                                config: {
+                                    mountPath: "/etc/riot-web/config.json",
+                                    subPath: "config.json",
+                                },
+                            },
+                        },
+                    },
+                },
+            },
+        },
+    },
+
+    svc: kube.Service("synapse") {
+        metadata+: app.metadata("synapse"),
+        target_pod:: app.deployment.spec.template,
+        spec+: {
+            ports: [
+                { name: "http", port: 8008, protocol: "TCP" },
+            ],
+            type: "ClusterIP",
+        },
+    },
+
+    riotSvc: kube.Service("riot-web") {
+        metadata+: app.metadata("riot-web"),
+        target_pod:: app.riotDeployment.spec.template,
+        spec+: {
+            ports: [
+                { name: "http", port: 80, protocol: "TCP" },
+            ],
+            type: "ClusterIP",
+        },
+    },
+
+    ingress: kube.Ingress("synapse") {
+        metadata+: app.metadata("synapse") {
+            annotations+: {
+                "kubernetes.io/tls-acme": "true",
+                "certmanager.k8s.io/cluster-issuer": "letsencrypt-prod",
+                "nginx.ingress.kubernetes.io/proxy-body-size": "0",
+            },
+        },
+        spec+: {
+            tls: [
+                {
+                    hosts: [cfg.domain],
+                    secretName: "synapse-tls",
+                },
+            ],
+            rules: [
+                {
+                    host: cfg.domain,
+                    http: {
+                        paths: [
+                            { path: "/", backend: app.riotSvc.name_port },
+                            { path: "/_matrix", backend: app.svc.name_port },
+                        ]
+                    },
+                }
+            ],
+        },
+    },
+}