diff --git a/apps/fc-chat/fc-chat.yaml b/apps/fc-chat/fc-chat.yaml index 572210e..90d41dd 100644 --- a/apps/fc-chat/fc-chat.yaml +++ b/apps/fc-chat/fc-chat.yaml @@ -1,5 +1,206 @@ -# FlowerCore Chat — TLS + Ingress -# Deployment and Service managed by deploy script (not ArgoCD) +# FlowerCore Chat +# +# ArgoCD-managed workload plus TLS/Ingress. The chat-web-secret remains an +# out-of-band Secret until the values are moved into a 1Password-backed item; +# the Deployment references it as optional so GitOps can own the workload +# without storing secret material in this repo. +--- +apiVersion: v1 +kind: Namespace +metadata: + name: fc-chat + labels: + app.kubernetes.io/part-of: flowercore +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: chat-web-config + namespace: fc-chat + labels: + app.kubernetes.io/name: chat-web + app.kubernetes.io/part-of: flowercore +data: + ASPNETCORE_ENVIRONMENT: Production + ASPNETCORE_URLS: "http://+:8080" + ASPNETCORE_FORWARDEDHEADERS_ENABLED: "true" + FlowerCore__Auth__Enabled: "false" + FlowerCore__Auth__Oidc__Enabled: "true" + FlowerCore__Auth__Oidc__Authority: "https://id.iamworkin.lan/application/o/chat/" + FlowerCore__Auth__Oidc__Audience: "chat" + FlowerCore__Auth__Oidc__ClientId: "chat" + FlowerCore__Database__ConnectionStrings__Sqlite: "Data Source=/data/chat.db" + # Ollama target. Switched 2026-04-25 from edge1 Pi5 (10.0.57.17) to BLUEJAY-WS + # workstation (10.0.56.20, RX 9070 XT 16GB, OLLAMA_HOST=0.0.0.0:11434, Vulkan + # backend per feedback_rdna4_vulkan_broken). The Pi5 was timing out every team- + # round speaker at the 300s per-turn cap (live-proven 2026-04-25 03:53 UTC, + # see feedback_chat_team_round_edge1_too_slow). Workstation has gemma3:4b for + # the Cheap tier, plus gemma3:27b/phi4:14b/qwen3:14b for Default/Balanced/Deep. + # Piper TTS stays on edge1 below (different service, Pi handles TTS fine). + FlowerCore__AI__OllamaBaseUrl: "http://10.0.56.20:11434" + FlowerCore__AI__DefaultModelName: "phi4:14b" + ChatOptions__BehaviorRuleEngine__OllamaBaseUrl: "http://10.0.56.20:11434" + ChatOptions__BehaviorRuleEngine__FallbackOllamaBaseUrl: "http://10.0.57.17:11434" + ChatOptions__BehaviorRuleEngine__ModelName: "gemma3:12b" + FlowerCore__AI__Memory__UseSharedIndexingAdapter: "true" + FlowerCore__AI__Memory__UseOllamaEmbeddings: "true" + FlowerCore__AI__Memory__EmbeddingModel: "nomic-embed-text" + FlowerCore__AI__Memory__EnableSharedIndexingBackfill: "true" + FlowerCore__AI__Memory__SharedIndexingDatabasePath: "/data/chat-memory-index.db" + FlowerCore__AI__Skills__Library__LibraryApiUrl: "http://library-web.fc-library.svc.cluster.local" + FlowerCore__AI__Skills__Retail__RetailApiUrl: "http://retail-web.fc-retail.svc.cluster.local" + FlowerCore__AI__Skills__Intranet__IntranetBaseUrl: "http://intranet-web.intranet.svc.cluster.local" + FlowerCore__AI__Skills__Print__PrintMcpBaseUrl: "http://10.0.57.16:5200" + FlowerCore__AI__IrcBridge__Enabled: "true" + FlowerCore__AI__IrcBridge__DefaultProfileSlug: "it-helpdesk" + FlowerCore__AI__IrcBridge__MentionProfileSlug: "it-helpdesk" + FlowerCore__AI__IrcBridge__MentionReactiveMode: "mentions-only" + FlowerCore__AI__IrcBridge__AllowActionExecution: "false" + FlowerCore__AI__Voice__Piper__Host: "10.0.57.17" + FlowerCore__AI__Voice__Piper__Port: "10400" + FlowerCore__AI__Voice__OutputRoot: "/data/audio" + FlowerCore__AI__Voice__RetentionDays: "30" + # LLM provider abstraction (ADR-088). Anthropic stays disabled here -- when + # an operator wants to enable Claude, they flip Enabled=true and mount + # FlowerCore__Anthropic__ApiKey from the onepassword-synced Secret (see + # docs/ai-agents/anthropic-integration.md). + FlowerCore__Anthropic__Enabled: "false" + FlowerCore__Anthropic__BaseUrl: "https://api.anthropic.com" + FlowerCore__Anthropic__DefaultModel: "claude-sonnet-4-6" + FlowerCore__Anthropic__CheapModel: "claude-haiku-4-5-20251001" + FlowerCore__Anthropic__DeepModel: "claude-opus-4-7" + FlowerCore__Budget__ResponseCacheEnabled: "true" + OTEL_SERVICE_NAME: FlowerCore.Chat + OTEL_EXPORTER_OTLP_ENDPOINT: "http://otel-collector.monitoring.svc.cluster.local:4317" + OTEL_EXPORTER_OTLP_PROTOCOL: grpc +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: chat-web-data + namespace: fc-chat + labels: + app.kubernetes.io/name: chat-web + app.kubernetes.io/part-of: flowercore +spec: + accessModes: + - ReadWriteOnce + storageClassName: longhorn + volumeMode: Filesystem + resources: + requests: + storage: 1Gi +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: chat-web + namespace: fc-chat + labels: + app.kubernetes.io/name: chat-web + app.kubernetes.io/part-of: flowercore +spec: + replicas: 1 + strategy: + type: Recreate + selector: + matchLabels: + app.kubernetes.io/name: chat-web + template: + metadata: + labels: + app.kubernetes.io/name: chat-web + app.kubernetes.io/part-of: flowercore + annotations: + prometheus.io/scrape: "true" + prometheus.io/port: "8080" + prometheus.io/path: "/metrics/prometheus" + spec: + nodeSelector: + kubernetes.io/hostname: rke2-server + securityContext: + fsGroup: 1654 + fsGroupChangePolicy: OnRootMismatch + containers: + - name: chat-web + image: localhost/fc-chat-web:v20260603-oidc-authentik + imagePullPolicy: Never + ports: + - name: http + containerPort: 8080 + envFrom: + - configMapRef: + name: chat-web-config + - secretRef: + name: chat-web-secret + optional: true + env: + - name: FlowerCore__Auth__Oidc__Authority + valueFrom: + secretKeyRef: + name: chat-oidc-client + key: issuer_url + optional: true + - name: FlowerCore__Auth__Oidc__ClientId + valueFrom: + secretKeyRef: + name: chat-oidc-client + key: client_id + optional: true + - name: FlowerCore__Auth__Oidc__ClientSecret + valueFrom: + secretKeyRef: + name: chat-oidc-client + key: client_secret + optional: true + volumeMounts: + - name: data + mountPath: /data + resources: + requests: + memory: "128Mi" + cpu: "100m" + limits: + memory: "512Mi" + cpu: "500m" + readinessProbe: + httpGet: + path: /healthz + port: 8080 + initialDelaySeconds: 10 + periodSeconds: 10 + timeoutSeconds: 5 + failureThreshold: 6 + livenessProbe: + httpGet: + path: /healthz + port: 8080 + initialDelaySeconds: 30 + periodSeconds: 30 + timeoutSeconds: 5 + failureThreshold: 3 + volumes: + - name: data + persistentVolumeClaim: + claimName: chat-web-data +--- +apiVersion: v1 +kind: Service +metadata: + name: chat-web + namespace: fc-chat + labels: + app.kubernetes.io/name: chat-web + app.kubernetes.io/part-of: flowercore +spec: + type: ClusterIP + selector: + app.kubernetes.io/name: chat-web + ports: + - name: http + port: 80 + targetPort: 8080 + protocol: TCP --- apiVersion: cert-manager.io/v1 kind: Certificate diff --git a/apps/knowledge/knowledge.yaml b/apps/knowledge/knowledge.yaml index 797997d..e843a9d 100644 --- a/apps/knowledge/knowledge.yaml +++ b/apps/knowledge/knowledge.yaml @@ -102,7 +102,7 @@ spec: - name: web # Placeholder tag — bump to the image you built + imported to ALL # RKE2 nodes via scripts/deploy-knowledge.sh before applying. - image: localhost/fc-knowledge-web:v20260429232635 + image: localhost/fc-knowledge-web:v20260603-oidc-authentik imagePullPolicy: Never command: - /bin/sh @@ -123,6 +123,25 @@ spec: value: "Production" - name: DOTNET_SYSTEM_GLOBALIZATION_INVARIANT value: "false" + # AuthentiK/OIDC is wired but not enforced until the + # knowledge-oidc-client Secret is provisioned and + # FlowerCore__Auth__Enabled is flipped to true. + - name: FlowerCore__Auth__Enabled + value: "false" + - name: FlowerCore__Auth__Oidc__Enabled + value: "true" + - name: FlowerCore__Auth__Oidc__Authority + value: "https://id.iamworkin.lan/application/o/knowledge/" + - name: FlowerCore__Auth__Oidc__Audience + value: "knowledge" + - name: FlowerCore__Auth__Oidc__ClientId + value: "knowledge" + - name: FlowerCore__Auth__Oidc__ClientSecret + valueFrom: + secretKeyRef: + name: knowledge-oidc-client + key: client_secret + optional: true # Vector-store directory + embedding model + edition profile dir. # Profile JSON is baked into the image at /home/app/editions via the # csproj Content-link from FlowerCore.Common/editions/.