Update telephony-web image tag to v20260324d (Scalar API docs, webhook config, surveys, templates, member portal)

This commit is contained in:
Andrew M. Stoltz
2026-03-24 15:55:24 -05:00
parent 848288af7a
commit 42d2894ed1

View File

@@ -1,349 +1,349 @@
# FlowerCore.Telephony - Blazor Server + REST API + Twilio IVR # FlowerCore.Telephony - Blazor Server + REST API + Twilio IVR
# ArgoCD managed - BlueJay Lab # ArgoCD managed - BlueJay Lab
# Credentials: 1Password → OnePasswordItem CRD → K8s Secret (twilio-credentials) # Credentials: 1Password → OnePasswordItem CRD → K8s Secret (twilio-credentials)
# TTS: Piper on edge1 (10.0.57.15:8500) # TTS: Piper on edge1 (10.0.57.15:8500)
# Public: telephony.flowercore.io via Cloudflare origin cert # Public: telephony.flowercore.io via Cloudflare origin cert
--- ---
apiVersion: v1 apiVersion: v1
kind: Namespace kind: Namespace
metadata: metadata:
name: telephony name: telephony
labels: labels:
app.kubernetes.io/part-of: bluejay-infra app.kubernetes.io/part-of: bluejay-infra
--- ---
# Cloudflare Origin Certificate for *.flowercore.io + *.iamwork.in (15-year RSA) # Cloudflare Origin Certificate for *.flowercore.io + *.iamwork.in (15-year RSA)
apiVersion: v1 apiVersion: v1
kind: Secret kind: Secret
metadata: metadata:
name: cf-origin-flowercore-io name: cf-origin-flowercore-io
namespace: telephony namespace: telephony
type: kubernetes.io/tls type: kubernetes.io/tls
data: data:
tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUVvRENDQTRpZ0F3SUJBZ0lVSXN4c1NKV1VRL0tqZ09ldk81YnNuVi9rZVE4d0RRWUpLb1pJaHZjTkFRRUwKQlFBd2dZc3hDekFKQmdOVkJBWVRBbFZUTVJrd0Z3WURWUVFLRXhCRGJHOTFaRVpzWVhKbExDQkpibU11TVRRdwpNZ1lEVlFRTEV5dERiRzkxWkVac1lYSmxJRTl5YVdkcGJpQlRVMHdnUTJWeWRHbG1hV05oZEdVZ1FYVjBhRzl5CmFYUjVNUll3RkFZRFZRUUhFdzFUWVc0Z1JuSmhibU5wYzJOdk1STXdFUVlEVlFRSUV3cERZV3hwWm05eWJtbGgKTUI0WERUSTJNRE14TURFMk16TXdNRm9YRFRReE1ETXdOakUyTXpNd01Gb3dZakVaTUJjR0ExVUVDaE1RUTJ4dgpkV1JHYkdGeVpTd2dTVzVqTGpFZE1Cc0dBMVVFQ3hNVVEyeHZkV1JHYkdGeVpTQlBjbWxuYVc0Z1EwRXhKakFrCkJnTlZCQU1USFVOc2IzVmtSbXhoY21VZ1QzSnBaMmx1SUVObGNuUnBabWxqWVhSbE1JSUJJakFOQmdrcWhraUcKOXcwQkFRRUZBQU9DQVE0QU1JSUJDZ0tDQVFFQXV0QmpkQ0xEdHdMQlZCU0Y1ZU1OMkt3ckIxTmZmRVhRMjlRRAo1aVR0dzJFcEZXNVJJSllkMjNrYUpCMU5jZXpHWlg4a0Q0cGEyWHpFZW1MVEtJNWw0MU11b3FoWjczNVE3U3RWCkVjRFFTT2ZYTkZQdFMwb0hqb0pRdGF2QjM0ZmJNR3l4Mmx0MU9HUzRNMGtLUWpBNWR6OTJQYjNyZ1RKR0JhOW4KeTZtVThncjRuUHRSdklxZ3NxdjRtMFA3dVU1YjE3NzU1Y2JLSDVoMzIxWHVjMDU4Tzl4M2JHQ0NuRUJXWDdqeApjRGhkUEs1Ri9XRjVBQnl5cFhIQ0ZxUUd4M1NVbmtCQ0ZQSmRabnMra3BHVUZWZGhud3B6NjBtNnlJSzQ0eVR4CjZqR3JOTFEyM1dOK2gwU1lCZU5vb2JBWThydkpiVlZEaGJqSVhBTWtFNGQzVll1TlhRSURBUUFCbzRJQklqQ0MKQVI0d0RnWURWUjBQQVFIL0JBUURBZ1dnTUIwR0ExVWRKUVFXTUJRR0NDc0dBUVVGQndNQ0JnZ3JCZ0VGQlFjRApBVEFNQmdOVkhSTUJBZjhFQWpBQU1CMEdBMVVkRGdRV0JCUkt1NkJVUDZ0N2dpbFRPay9FdEdKQ3R6N3dTREFmCkJnTlZIU01FR0RBV2dCUWs2Rk5YWFh3MFFJZXA2NVRidXVFV2VQd3BwREJBQmdnckJnRUZCUWNCQVFRME1ESXcKTUFZSUt3WUJCUVVITUFHR0pHaDBkSEE2THk5dlkzTndMbU5zYjNWa1pteGhjbVV1WTI5dEwyOXlhV2RwYmw5agpZVEFqQmdOVkhSRUVIREFhZ2d3cUxtbGhiWGR2Y21zdWFXNkNDbWxoYlhkdmNtc3VhVzR3T0FZRFZSMGZCREV3Ckx6QXRvQ3VnS1lZbmFIUjBjRG92TDJOeWJDNWpiRzkxWkdac1lYSmxMbU52YlM5dmNtbG5hVzVmWTJFdVkzSnMKTUEwR0NTcUdTSWIzRFFFQkN3VUFBNElCQVFDSjMvTGNleE5pb0lWdUxoemhmbTZCeDV2SWk3T25CaHF1WUlDdwplNnArZ0prdE16ZFJQcDV0bk03dllBWmxMajVJOTByWDRuczhJc3dEbzJBN2wwYTRGZVJFclFmRklsZXQzbjIyCjUxVTZYVElCSks5c1FZT0FkU3pJUzV1OUNKSFpBUTF5WmxSd3BBR3RVWnhxL1dpcGFWUTRwNXhrcEJNMVlZSlAKNW1jQ09HcFErSnpORlpQc2daYUJncDBYL1BBZkNJRkkyZld5QWE2elBqRm0rdDVXUXIrZlBaT2VUS2VIbWVzVgo3UlZxUUdEb3Q0eTY1NklEdmdmU2ZLRnFIRW9XNDJVbDBxQ05hMS9keEJld3NIS1VWWE1ETkdiQlNVQjM4TG9YCm1OQ3hJQlVOUjR0TG1CQUxZT3hVMnZhSWRCd0xBc2YrcndnVnVjUGpCUTc2VWMwUQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg== tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUVvRENDQTRpZ0F3SUJBZ0lVSXN4c1NKV1VRL0tqZ09ldk81YnNuVi9rZVE4d0RRWUpLb1pJaHZjTkFRRUwKQlFBd2dZc3hDekFKQmdOVkJBWVRBbFZUTVJrd0Z3WURWUVFLRXhCRGJHOTFaRVpzWVhKbExDQkpibU11TVRRdwpNZ1lEVlFRTEV5dERiRzkxWkVac1lYSmxJRTl5YVdkcGJpQlRVMHdnUTJWeWRHbG1hV05oZEdVZ1FYVjBhRzl5CmFYUjVNUll3RkFZRFZRUUhFdzFUWVc0Z1JuSmhibU5wYzJOdk1STXdFUVlEVlFRSUV3cERZV3hwWm05eWJtbGgKTUI0WERUSTJNRE14TURFMk16TXdNRm9YRFRReE1ETXdOakUyTXpNd01Gb3dZakVaTUJjR0ExVUVDaE1RUTJ4dgpkV1JHYkdGeVpTd2dTVzVqTGpFZE1Cc0dBMVVFQ3hNVVEyeHZkV1JHYkdGeVpTQlBjbWxuYVc0Z1EwRXhKakFrCkJnTlZCQU1USFVOc2IzVmtSbXhoY21VZ1QzSnBaMmx1SUVObGNuUnBabWxqWVhSbE1JSUJJakFOQmdrcWhraUcKOXcwQkFRRUZBQU9DQVE0QU1JSUJDZ0tDQVFFQXV0QmpkQ0xEdHdMQlZCU0Y1ZU1OMkt3ckIxTmZmRVhRMjlRRAo1aVR0dzJFcEZXNVJJSllkMjNrYUpCMU5jZXpHWlg4a0Q0cGEyWHpFZW1MVEtJNWw0MU11b3FoWjczNVE3U3RWCkVjRFFTT2ZYTkZQdFMwb0hqb0pRdGF2QjM0ZmJNR3l4Mmx0MU9HUzRNMGtLUWpBNWR6OTJQYjNyZ1RKR0JhOW4KeTZtVThncjRuUHRSdklxZ3NxdjRtMFA3dVU1YjE3NzU1Y2JLSDVoMzIxWHVjMDU4Tzl4M2JHQ0NuRUJXWDdqeApjRGhkUEs1Ri9XRjVBQnl5cFhIQ0ZxUUd4M1NVbmtCQ0ZQSmRabnMra3BHVUZWZGhud3B6NjBtNnlJSzQ0eVR4CjZqR3JOTFEyM1dOK2gwU1lCZU5vb2JBWThydkpiVlZEaGJqSVhBTWtFNGQzVll1TlhRSURBUUFCbzRJQklqQ0MKQVI0d0RnWURWUjBQQVFIL0JBUURBZ1dnTUIwR0ExVWRKUVFXTUJRR0NDc0dBUVVGQndNQ0JnZ3JCZ0VGQlFjRApBVEFNQmdOVkhSTUJBZjhFQWpBQU1CMEdBMVVkRGdRV0JCUkt1NkJVUDZ0N2dpbFRPay9FdEdKQ3R6N3dTREFmCkJnTlZIU01FR0RBV2dCUWs2Rk5YWFh3MFFJZXA2NVRidXVFV2VQd3BwREJBQmdnckJnRUZCUWNCQVFRME1ESXcKTUFZSUt3WUJCUVVITUFHR0pHaDBkSEE2THk5dlkzTndMbU5zYjNWa1pteGhjbVV1WTI5dEwyOXlhV2RwYmw5agpZVEFqQmdOVkhSRUVIREFhZ2d3cUxtbGhiWGR2Y21zdWFXNkNDbWxoYlhkdmNtc3VhVzR3T0FZRFZSMGZCREV3Ckx6QXRvQ3VnS1lZbmFIUjBjRG92TDJOeWJDNWpiRzkxWkdac1lYSmxMbU52YlM5dmNtbG5hVzVmWTJFdVkzSnMKTUEwR0NTcUdTSWIzRFFFQkN3VUFBNElCQVFDSjMvTGNleE5pb0lWdUxoemhmbTZCeDV2SWk3T25CaHF1WUlDdwplNnArZ0prdE16ZFJQcDV0bk03dllBWmxMajVJOTByWDRuczhJc3dEbzJBN2wwYTRGZVJFclFmRklsZXQzbjIyCjUxVTZYVElCSks5c1FZT0FkU3pJUzV1OUNKSFpBUTF5WmxSd3BBR3RVWnhxL1dpcGFWUTRwNXhrcEJNMVlZSlAKNW1jQ09HcFErSnpORlpQc2daYUJncDBYL1BBZkNJRkkyZld5QWE2elBqRm0rdDVXUXIrZlBaT2VUS2VIbWVzVgo3UlZxUUdEb3Q0eTY1NklEdmdmU2ZLRnFIRW9XNDJVbDBxQ05hMS9keEJld3NIS1VWWE1ETkdiQlNVQjM4TG9YCm1OQ3hJQlVOUjR0TG1CQUxZT3hVMnZhSWRCd0xBc2YrcndnVnVjUGpCUTc2VWMwUQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==
tls.key: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JSUV2UUlCQURBTkJna3Foa2lHOXcwQkFRRUZBQVNDQktjd2dnU2pBZ0VBQW9JQkFRQzYwR04wSXNPM0FzRlUKRklYbDR3M1lyQ3NIYTE5OFJkRGIxQVBtSk8zRFlTa1ZibEVnbGgzYmVSb2tIVTF4N01abGZ5UVBpbHJaZk1SNgpZdE1vam1YalV5NmlxRm52ZmxEdEsxVVJ3TkJJNTljMFUrMUxTZ2VPZ2xDMXE4SGZoOXN3YkxIYVczVTRaTGd6ClNRcENNRGwzUDNZOXZldUJNa1lGcjJmTHFaVHlDdmljKzFHOGlxQ3lxL2liUS91NVRsdlh2dm5seHNvZm1IZmIKVmU1elRudzczSGRzWUlLY1FGWmZ1UEZ3T0YwOHJrWDlZWGtBSExLbGNjSVdwQWJIZEpTZVFFSVU4bDFtZXo2UwprWlFWVjJHZkNuUHJTYnJJZ3JqakpQSHFNYXMwdERiZFkzNkhSSmdGNDJpaHNCanl1OGx0VlVPRnVNaGNBeVFUCmgzZFZpNDFkQWdNQkFBRUNnZ0VBTGlseXZkNmVTcEYvZUxtV2lhTVV4NUxwa2dhWHpITkxCQnNNZUpqcytLL0EKVVdlZ1crTkVUdmlLalZ5QlI5SzRocG1IYldDa2lPUDBBQUwrQnlKQ3lvekNOQmJTSEdRejlwc1R5dzZBV1ZlUwpuYjlVWGx1VmFQRktKTTRqbXNydERuYjVic25WT2lGblErTDdTalkwNlFMUlFybjBvUWp0ZFJldUdBMFlQVU90CkhSYzNsMFg2ZHJqdkJYY2prWTQwWm9ZYkRrelJnU1JWbWVOUGFIbjZPR0NtYUVUMXVyK01qYVZ2ME9lbEdIWncKVzljSEIxaHNxRzUvMWU3V0RQN0l0cjkwTmg4ay81NVhiK3lQUnhsRFd5bWtZMzIvdFBtZzdESTRKV2tRRWt3cgpIZUtwODVTcE5ta1liRnVpVFppeU8zZDZ0aXZHNHhFZW8rSzFVVFU4c1FLQmdRRFRNSEU1RDFYVC9HbGR5VHNsCllrODRVL1N0NXUrK2RIUEt1Wmw2dVB0UGgxV1lrdnFRcmdrL05YanVud2xGN0Y3b2tWOGdPeWxreTYwYTZkcXIKeXZwN1ZJdXYzekVlc2h2NjNWMlpaVkMzcXZYSzFheit3Zmx3NitCZmVuRlY5S2NENHN0dTdwOFRPWmFGN01CUgo3YXZzaXVXbWtqdmM1TlVLRmVDRTY0SnZFUUtCZ1FEaWMrbWlNLzBodDN1ajhuOXgyMDFQZFNqbEpVaUc1NjNNCnRYZlBCdDJRT0NhaVluUFNFdTdXdm5pQWRFL2xrMm91cFRWam9LYmZPbDFyQjd6UzVhc2kxdVdDZDhlUy9UWGIKdU5iRmlNMDB4L3JxalMydCtQbTd4MVhrYTB4TFNSRDNmZ0tSQldSN3pscStkYWZ1WE1qelUxRnh5dTIycGphRgpIMEl3NEpCUmpRS0JnUUNOaWhMb0Rob1V5RCtKNXJzb00vb3FJMEtDWnB0WlJzendHbkg5cVFwdFk2Ti9iVXBYCk92emhpeUh3czAvUXVEbG5uejVrNktHMmR6Y2VLWXN2eGdzWUt6S3ZmV043VWgya2hVWWM3NlVvWTREMkh6MGgKUkxtNzc2cGg4enNRUTdiSHlQRlUrTUpPYlRNdnNOdTRUUlVEcEplRGl0QnFIRWVYeWMrKzVlUjJNUUtCZ0h2UgptVHVoWlpVYitEVEtrVGkyQ20yWnlBU1RBRGNUVW9xTjVyYUNNSDk4MUZNUnRmWjFkN1pmYXhBQmlQWWtSbmkrCnlKUnk4UXM1cEg2ek9tR3VSb2JFTGJYS3ZJcjRmSXhwWXJXYmVXaVV0L09yd2dCUUZHekNMNHEzeUgyWnMvYy8KSlRRYVdMa0JPY2pPR0VaUzRXVjZkeHZiTTJNZE9zNUxLeXdDZmFhNUFvR0FIQUE1eEN0dndOZE4xeExndkZ3RApPK2lyMDl1bXMxOFBzSVpmK1ZrWGtpcHF4MWNUT0hEanpPR01yWXV0M2FFeE00Zjd2ckFHRFMyY2pwZjM0T1JxCit4Y2gwWlNaQ2FDZmlnZG9OelNkcDFLcmo0cnFKdG5ZdS9CNDlDQlVoSDBNaCtSRWswQ0hHOVE4b3FOWFk0V0wKbVVOVTZMYUkwQWtvSzNVb2tWQVJEYXM9Ci0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0K tls.key: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JSUV2UUlCQURBTkJna3Foa2lHOXcwQkFRRUZBQVNDQktjd2dnU2pBZ0VBQW9JQkFRQzYwR04wSXNPM0FzRlUKRklYbDR3M1lyQ3NIYTE5OFJkRGIxQVBtSk8zRFlTa1ZibEVnbGgzYmVSb2tIVTF4N01abGZ5UVBpbHJaZk1SNgpZdE1vam1YalV5NmlxRm52ZmxEdEsxVVJ3TkJJNTljMFUrMUxTZ2VPZ2xDMXE4SGZoOXN3YkxIYVczVTRaTGd6ClNRcENNRGwzUDNZOXZldUJNa1lGcjJmTHFaVHlDdmljKzFHOGlxQ3lxL2liUS91NVRsdlh2dm5seHNvZm1IZmIKVmU1elRudzczSGRzWUlLY1FGWmZ1UEZ3T0YwOHJrWDlZWGtBSExLbGNjSVdwQWJIZEpTZVFFSVU4bDFtZXo2UwprWlFWVjJHZkNuUHJTYnJJZ3JqakpQSHFNYXMwdERiZFkzNkhSSmdGNDJpaHNCanl1OGx0VlVPRnVNaGNBeVFUCmgzZFZpNDFkQWdNQkFBRUNnZ0VBTGlseXZkNmVTcEYvZUxtV2lhTVV4NUxwa2dhWHpITkxCQnNNZUpqcytLL0EKVVdlZ1crTkVUdmlLalZ5QlI5SzRocG1IYldDa2lPUDBBQUwrQnlKQ3lvekNOQmJTSEdRejlwc1R5dzZBV1ZlUwpuYjlVWGx1VmFQRktKTTRqbXNydERuYjVic25WT2lGblErTDdTalkwNlFMUlFybjBvUWp0ZFJldUdBMFlQVU90CkhSYzNsMFg2ZHJqdkJYY2prWTQwWm9ZYkRrelJnU1JWbWVOUGFIbjZPR0NtYUVUMXVyK01qYVZ2ME9lbEdIWncKVzljSEIxaHNxRzUvMWU3V0RQN0l0cjkwTmg4ay81NVhiK3lQUnhsRFd5bWtZMzIvdFBtZzdESTRKV2tRRWt3cgpIZUtwODVTcE5ta1liRnVpVFppeU8zZDZ0aXZHNHhFZW8rSzFVVFU4c1FLQmdRRFRNSEU1RDFYVC9HbGR5VHNsCllrODRVL1N0NXUrK2RIUEt1Wmw2dVB0UGgxV1lrdnFRcmdrL05YanVud2xGN0Y3b2tWOGdPeWxreTYwYTZkcXIKeXZwN1ZJdXYzekVlc2h2NjNWMlpaVkMzcXZYSzFheit3Zmx3NitCZmVuRlY5S2NENHN0dTdwOFRPWmFGN01CUgo3YXZzaXVXbWtqdmM1TlVLRmVDRTY0SnZFUUtCZ1FEaWMrbWlNLzBodDN1ajhuOXgyMDFQZFNqbEpVaUc1NjNNCnRYZlBCdDJRT0NhaVluUFNFdTdXdm5pQWRFL2xrMm91cFRWam9LYmZPbDFyQjd6UzVhc2kxdVdDZDhlUy9UWGIKdU5iRmlNMDB4L3JxalMydCtQbTd4MVhrYTB4TFNSRDNmZ0tSQldSN3pscStkYWZ1WE1qelUxRnh5dTIycGphRgpIMEl3NEpCUmpRS0JnUUNOaWhMb0Rob1V5RCtKNXJzb00vb3FJMEtDWnB0WlJzendHbkg5cVFwdFk2Ti9iVXBYCk92emhpeUh3czAvUXVEbG5uejVrNktHMmR6Y2VLWXN2eGdzWUt6S3ZmV043VWgya2hVWWM3NlVvWTREMkh6MGgKUkxtNzc2cGg4enNRUTdiSHlQRlUrTUpPYlRNdnNOdTRUUlVEcEplRGl0QnFIRWVYeWMrKzVlUjJNUUtCZ0h2UgptVHVoWlpVYitEVEtrVGkyQ20yWnlBU1RBRGNUVW9xTjVyYUNNSDk4MUZNUnRmWjFkN1pmYXhBQmlQWWtSbmkrCnlKUnk4UXM1cEg2ek9tR3VSb2JFTGJYS3ZJcjRmSXhwWXJXYmVXaVV0L09yd2dCUUZHekNMNHEzeUgyWnMvYy8KSlRRYVdMa0JPY2pPR0VaUzRXVjZkeHZiTTJNZE9zNUxLeXdDZmFhNUFvR0FIQUE1eEN0dndOZE4xeExndkZ3RApPK2lyMDl1bXMxOFBzSVpmK1ZrWGtpcHF4MWNUT0hEanpPR01yWXV0M2FFeE00Zjd2ckFHRFMyY2pwZjM0T1JxCit4Y2gwWlNaQ2FDZmlnZG9OelNkcDFLcmo0cnFKdG5ZdS9CNDlDQlVoSDBNaCtSRWswQ0hHOVE4b3FOWFk0V0wKbVVOVTZMYUkwQWtvSzNVb2tWQVJEYXM9Ci0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0K
--- ---
# 1Password → K8s Secret sync for Twilio credentials # 1Password → K8s Secret sync for Twilio credentials
# Creates secret "twilio-credentials" with fields: AccountSid, AuthToken, DefaultFromNumber # Creates secret "twilio-credentials" with fields: AccountSid, AuthToken, DefaultFromNumber
apiVersion: onepassword.com/v1 apiVersion: onepassword.com/v1
kind: OnePasswordItem kind: OnePasswordItem
metadata: metadata:
name: twilio-credentials name: twilio-credentials
namespace: telephony namespace: telephony
spec: spec:
itemPath: "vaults/IAmWorkin/items/Twilio Account" itemPath: "vaults/IAmWorkin/items/Twilio Account"
--- ---
# Application configuration overlay # Application configuration overlay
apiVersion: v1 apiVersion: v1
kind: ConfigMap kind: ConfigMap
metadata: metadata:
name: telephony-config name: telephony-config
namespace: telephony namespace: telephony
data: data:
appsettings.Production.json: | appsettings.Production.json: |
{ {
"Telephony": { "Telephony": {
"Provider": "asterisk", "Provider": "asterisk",
"Twilio": { "Twilio": {
"VoiceUrl": "https://telephony.flowercore.io/api/twilio/webhooks/voice/incoming", "VoiceUrl": "https://telephony.flowercore.io/api/twilio/webhooks/voice/incoming",
"StatusCallbackUrl": "https://telephony.flowercore.io/api/twilio/webhooks/voice/status" "StatusCallbackUrl": "https://telephony.flowercore.io/api/twilio/webhooks/voice/status"
}, },
"Asterisk": { "Asterisk": {
"BaseUrl": "http://localhost:8088", "BaseUrl": "http://localhost:8088",
"Username": "flowercore", "Username": "flowercore",
"Password": "bluejay-asterisk-ari", "Password": "bluejay-asterisk-ari",
"Application": "flowercore-pbx", "Application": "flowercore-pbx",
"ReconnectDelaySeconds": 5, "ReconnectDelaySeconds": 5,
"MaxReconnectDelaySeconds": 60 "MaxReconnectDelaySeconds": 60
} }
}, },
"Ari": { "Ari": {
"BaseUrl": "http://localhost:8088", "BaseUrl": "http://localhost:8088",
"Username": "flowercore", "Username": "flowercore",
"Password": "bluejay-asterisk-ari", "Password": "bluejay-asterisk-ari",
"Application": "flowercore-pbx", "Application": "flowercore-pbx",
"ReconnectDelaySeconds": 5, "ReconnectDelaySeconds": 5,
"MaxReconnectDelaySeconds": 60 "MaxReconnectDelaySeconds": 60
}, },
"Tts": { "Tts": {
"PiperUrl": "http://10.0.57.15:8500", "PiperUrl": "http://10.0.57.15:8500",
"DefaultEngine": "piper", "DefaultEngine": "piper",
"SampleRate": 8000 "SampleRate": 8000
}, },
"DatabaseProvider": "Sqlite", "DatabaseProvider": "Sqlite",
"ConnectionStrings": { "ConnectionStrings": {
"DefaultConnection": "Data Source=/data/telephony.db" "DefaultConnection": "Data Source=/data/telephony.db"
}, },
"Kestrel": { "Kestrel": {
"Endpoints": { "Endpoints": {
"Http": { "Url": "http://0.0.0.0:5100" } "Http": { "Url": "http://0.0.0.0:5100" }
} }
} }
} }
--- ---
# Persistent volume for SQLite database # Persistent volume for SQLite database
apiVersion: v1 apiVersion: v1
kind: PersistentVolumeClaim kind: PersistentVolumeClaim
metadata: metadata:
name: telephony-data name: telephony-data
namespace: telephony namespace: telephony
spec: spec:
accessModes: [ReadWriteOnce] accessModes: [ReadWriteOnce]
resources: resources:
requests: requests:
storage: 5Gi storage: 5Gi
--- ---
# Telephony web application # Telephony web application
apiVersion: apps/v1 apiVersion: apps/v1
kind: Deployment kind: Deployment
metadata: metadata:
name: telephony-web name: telephony-web
namespace: telephony namespace: telephony
labels: labels:
app: telephony-web app: telephony-web
spec: spec:
replicas: 1 replicas: 1
strategy: strategy:
type: Recreate type: Recreate
selector: selector:
matchLabels: matchLabels:
app: telephony-web app: telephony-web
template: template:
metadata: metadata:
labels: labels:
app: telephony-web app: telephony-web
spec: spec:
securityContext: securityContext:
fsGroup: 1654 fsGroup: 1654
initContainers: initContainers:
- name: fix-data-perms - name: fix-data-perms
image: busybox:latest image: busybox:latest
command: ["sh", "-c", "chown -R 1654:1654 /data"] command: ["sh", "-c", "chown -R 1654:1654 /data"]
volumeMounts: volumeMounts:
- name: telephony-data - name: telephony-data
mountPath: /data mountPath: /data
hostNetwork: true hostNetwork: true
dnsPolicy: ClusterFirstWithHostNet dnsPolicy: ClusterFirstWithHostNet
affinity: affinity:
podAffinity: podAffinity:
requiredDuringSchedulingIgnoredDuringExecution: requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector: - labelSelector:
matchLabels: matchLabels:
app: asterisk app: asterisk
topologyKey: kubernetes.io/hostname topologyKey: kubernetes.io/hostname
containers: containers:
- name: telephony-web - name: telephony-web
image: localhost/fc-telephony-web:latest image: localhost/fc-telephony-web:v20260324d
imagePullPolicy: Never imagePullPolicy: Never
ports: ports:
- containerPort: 5100 - containerPort: 5100
name: http name: http
env: env:
- name: Telephony__Twilio__AccountSid - name: Telephony__Twilio__AccountSid
valueFrom: valueFrom:
secretKeyRef: secretKeyRef:
name: twilio-credentials name: twilio-credentials
key: AccountSid key: AccountSid
optional: true optional: true
- name: Telephony__Twilio__AuthToken - name: Telephony__Twilio__AuthToken
valueFrom: valueFrom:
secretKeyRef: secretKeyRef:
name: twilio-credentials name: twilio-credentials
key: AuthToken key: AuthToken
optional: true optional: true
- name: Telephony__Twilio__DefaultFromNumber - name: Telephony__Twilio__DefaultFromNumber
valueFrom: valueFrom:
secretKeyRef: secretKeyRef:
name: twilio-credentials name: twilio-credentials
key: DefaultFromNumber key: DefaultFromNumber
optional: true optional: true
volumeMounts: volumeMounts:
- name: telephony-config - name: telephony-config
mountPath: /app/appsettings.Production.json mountPath: /app/appsettings.Production.json
subPath: appsettings.Production.json subPath: appsettings.Production.json
readOnly: true readOnly: true
- name: telephony-data - name: telephony-data
mountPath: /data mountPath: /data
resources: resources:
requests: requests:
memory: 256Mi memory: 256Mi
cpu: 100m cpu: 100m
limits: limits:
memory: 1Gi memory: 1Gi
cpu: "1" cpu: "1"
livenessProbe: livenessProbe:
httpGet: httpGet:
path: /health path: /health
port: 5100 port: 5100
initialDelaySeconds: 30 initialDelaySeconds: 30
periodSeconds: 10 periodSeconds: 10
readinessProbe: readinessProbe:
httpGet: httpGet:
path: /health path: /health
port: 5100 port: 5100
initialDelaySeconds: 10 initialDelaySeconds: 10
periodSeconds: 5 periodSeconds: 5
volumes: volumes:
- name: telephony-config - name: telephony-config
configMap: configMap:
name: telephony-config name: telephony-config
- name: telephony-data - name: telephony-data
persistentVolumeClaim: persistentVolumeClaim:
claimName: telephony-data claimName: telephony-data
--- ---
# ClusterIP service # ClusterIP service
apiVersion: v1 apiVersion: v1
kind: Service kind: Service
metadata: metadata:
name: telephony-web name: telephony-web
namespace: telephony namespace: telephony
spec: spec:
selector: selector:
app: telephony-web app: telephony-web
ports: ports:
- port: 5100 - port: 5100
targetPort: 5100 targetPort: 5100
name: http name: http
--- ---
# Traefik IngressRoute — public via Cloudflare (primary: flowercore.io) # Traefik IngressRoute — public via Cloudflare (primary: flowercore.io)
apiVersion: traefik.io/v1alpha1 apiVersion: traefik.io/v1alpha1
kind: IngressRoute kind: IngressRoute
metadata: metadata:
name: telephony-web name: telephony-web
namespace: telephony namespace: telephony
spec: spec:
entryPoints: entryPoints:
- websecure - websecure
routes: routes:
- kind: Rule - kind: Rule
match: Host(`telephony.flowercore.io`) match: Host(`telephony.flowercore.io`)
services: services:
- name: telephony-web - name: telephony-web
port: 5100 port: 5100
- kind: Rule - kind: Rule
match: Host(`telephony.iamwork.in`) match: Host(`telephony.iamwork.in`)
services: services:
- name: telephony-web - name: telephony-web
port: 5100 port: 5100
tls: tls:
secretName: cf-origin-flowercore-io secretName: cf-origin-flowercore-io
--- ---
# NetworkPolicy: deny-all baseline + Traefik ingress + SIP/RTP ingress + DNS egress + TTS egress # NetworkPolicy: deny-all baseline + Traefik ingress + SIP/RTP ingress + DNS egress + TTS egress
apiVersion: networking.k8s.io/v1 apiVersion: networking.k8s.io/v1
kind: NetworkPolicy kind: NetworkPolicy
metadata: metadata:
name: telephony-netpol name: telephony-netpol
namespace: telephony namespace: telephony
spec: spec:
podSelector: {} podSelector: {}
policyTypes: policyTypes:
- Ingress - Ingress
- Egress - Egress
ingress: ingress:
# Allow Traefik ingress controller # Allow Traefik ingress controller
- from: - from:
- namespaceSelector: - namespaceSelector:
matchLabels: matchLabels:
kubernetes.io/metadata.name: traefik-system kubernetes.io/metadata.name: traefik-system
# Allow Selenium Grid for automated UI testing # Allow Selenium Grid for automated UI testing
- from: - from:
- namespaceSelector: - namespaceSelector:
matchLabels: matchLabels:
kubernetes.io/metadata.name: selenium kubernetes.io/metadata.name: selenium
ports: ports:
- port: 5100 - port: 5100
protocol: TCP protocol: TCP
# Allow SIP/RTP from external sources (Yealink phones, Twilio SIP trunk) # Allow SIP/RTP from external sources (Yealink phones, Twilio SIP trunk)
- from: - from:
- ipBlock: - ipBlock:
cidr: 0.0.0.0/0 cidr: 0.0.0.0/0
ports: ports:
- port: 5060 - port: 5060
protocol: UDP protocol: UDP
- port: 5060 - port: 5060
protocol: TCP protocol: TCP
- port: 10000 - port: 10000
endPort: 20000 endPort: 20000
protocol: UDP protocol: UDP
egress: egress:
# Allow DNS resolution (CoreDNS in kube-system) # Allow DNS resolution (CoreDNS in kube-system)
- to: - to:
- namespaceSelector: - namespaceSelector:
matchLabels: matchLabels:
kubernetes.io/metadata.name: kube-system kubernetes.io/metadata.name: kube-system
ports: ports:
- port: 53 - port: 53
protocol: UDP protocol: UDP
- port: 53 - port: 53
protocol: TCP protocol: TCP
# Allow Piper TTS on edge1 (10.0.57.15:8500) # Allow Piper TTS on edge1 (10.0.57.15:8500)
- to: - to:
- ipBlock: - ipBlock:
cidr: 10.0.57.15/32 cidr: 10.0.57.15/32
ports: ports:
- port: 8500 - port: 8500
protocol: TCP protocol: TCP
# Allow Twilio API outbound (HTTPS) # Allow Twilio API outbound (HTTPS)
- to: - to:
- ipBlock: - ipBlock:
cidr: 0.0.0.0/0 cidr: 0.0.0.0/0
except: except:
- 10.0.0.0/8 - 10.0.0.0/8
- 172.16.0.0/12 - 172.16.0.0/12
- 192.168.0.0/16 - 192.168.0.0/16
ports: ports:
- port: 443 - port: 443
protocol: TCP protocol: TCP
# Allow SIP/RTP responses (Asterisk → phones and Twilio) # Allow SIP/RTP responses (Asterisk → phones and Twilio)
- to: - to:
- ipBlock: - ipBlock:
cidr: 0.0.0.0/0 cidr: 0.0.0.0/0
ports: ports:
- port: 5060 - port: 5060
protocol: UDP protocol: UDP
- port: 5060 - port: 5060
protocol: TCP protocol: TCP
- port: 10000 - port: 10000
endPort: 20000 endPort: 20000
protocol: UDP protocol: UDP
# Allow 1Password Connect for secret sync # Allow 1Password Connect for secret sync
- to: - to:
- namespaceSelector: - namespaceSelector:
matchLabels: matchLabels:
kubernetes.io/metadata.name: onepassword-system kubernetes.io/metadata.name: onepassword-system
--- ---
# TLS Certificate for internal hostname via cert-manager # TLS Certificate for internal hostname via cert-manager
apiVersion: cert-manager.io/v1 apiVersion: cert-manager.io/v1
kind: Certificate kind: Certificate
metadata: metadata:
name: telephony-internal-tls name: telephony-internal-tls
namespace: telephony namespace: telephony
spec: spec:
secretName: telephony-internal-tls secretName: telephony-internal-tls
issuerRef: issuerRef:
name: step-ca-acme name: step-ca-acme
kind: ClusterIssuer kind: ClusterIssuer
dnsNames: dnsNames:
- telephony.iamworkin.lan - telephony.iamworkin.lan
--- ---
# Traefik IngressRoute — internal LAN access # Traefik IngressRoute — internal LAN access
apiVersion: traefik.io/v1alpha1 apiVersion: traefik.io/v1alpha1
kind: IngressRoute kind: IngressRoute
metadata: metadata:
name: telephony-web-internal name: telephony-web-internal
namespace: telephony namespace: telephony
spec: spec:
entryPoints: entryPoints:
- websecure - websecure
routes: routes:
- kind: Rule - kind: Rule
match: Host(`telephony.iamworkin.lan`) match: Host(`telephony.iamworkin.lan`)
services: services:
- name: telephony-web - name: telephony-web
port: 5100 port: 5100
tls: tls:
secretName: telephony-internal-tls secretName: telephony-internal-tls