redesign fully scaffolded and web login works

This commit is contained in:
2026-03-17 20:10:47 -04:00
parent b9cc397e05
commit f6bd22a8ef
143 changed files with 17317 additions and 693 deletions

View File

@@ -47,8 +47,8 @@ deploy/k8s/
bin/dev start
# Access the application
# Web UI: http://dexorder.local/cryptochimp/
# Backend: ws://dexorder.local/ws
# Web UI: http://dexorder.local/
# Gateway: http://dexorder.local/api
# In another terminal, start tunnel for ingress
bin/dev tunnel

View File

@@ -0,0 +1,26 @@
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: gateway-ingress
annotations:
cert-manager.io/cluster-issuer: "letsencrypt-prod"
nginx.ingress.kubernetes.io/rewrite-target: /$1
spec:
ingressClassName: nginx
tls:
- hosts:
- dexorder.ai
secretName: gateway-tls
rules:
- host: dexorder.ai
http:
paths:
# Gateway API routes - strip /api prefix
- path: /api/(.*)
pathType: ImplementationSpecific
backend:
service:
name: gateway
port:
number: 3000

View File

@@ -7,7 +7,6 @@ apiVersion: v1
kind: ServiceAccount
metadata:
name: gateway
namespace: dexorder-system
---
# Role scoped to dexorder-agents namespace only
apiVersion: rbac.authorization.k8s.io/v1
@@ -20,27 +19,27 @@ rules:
- apiGroups: ["apps"]
resources: ["deployments"]
verbs: ["create", "get", "list", "watch", "patch", "update"]
# PVCs: create and read (deletion handled by sidecar)
- apiGroups: [""]
resources: ["persistentvolumeclaims"]
verbs: ["create", "get", "list", "watch"]
# Services: create and manage agent MCP endpoints
- apiGroups: [""]
resources: ["services"]
verbs: ["create", "get", "list", "watch", "patch", "update"]
# Read-only pod access for status checks (no exec!)
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list", "watch"]
# Pod logs for debugging (read-only)
- apiGroups: [""]
resources: ["pods/log"]
verbs: ["get"]
# Explicitly NOT included:
# - deployments/delete - handled by lifecycle sidecar
# - pvc/delete - handled by lifecycle sidecar
@@ -58,7 +57,7 @@ metadata:
subjects:
- kind: ServiceAccount
name: gateway
namespace: dexorder-system
namespace: default
roleRef:
kind: Role
name: agent-creator

View File

@@ -0,0 +1,101 @@
# Gateway deployment
# Multi-channel gateway with automatic container provisioning
---
apiVersion: v1
kind: Service
metadata:
name: gateway
spec:
selector:
app: gateway
ports:
- name: http
protocol: TCP
port: 3000
targetPort: http
type: ClusterIP
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: gateway
labels:
app: gateway
spec:
replicas: 1
selector:
matchLabels:
app: gateway
template:
metadata:
labels:
app: gateway
spec:
serviceAccountName: gateway
initContainers:
- name: wait-for-postgres
image: busybox:1.36
command: ['sh', '-c', 'until nc -z postgres 5432; do echo waiting for postgres; sleep 2; done;']
- name: wait-for-dragonfly
image: busybox:1.36
command: ['sh', '-c', 'until nc -z dragonfly 6379; do echo waiting for dragonfly; sleep 2; done;']
- name: wait-for-qdrant
image: busybox:1.36
command: ['sh', '-c', 'until nc -z qdrant 6333; do echo waiting for qdrant; sleep 2; done;']
volumes:
- name: config
configMap:
name: gateway-config
- name: secrets
secret:
secretName: gateway-secrets
containers:
- name: gateway
image: ghcr.io/dexorder/gateway:latest
imagePullPolicy: Always
ports:
- name: http
containerPort: 3000
protocol: TCP
volumeMounts:
- name: config
mountPath: /config/config.yaml
subPath: config.yaml
readOnly: true
- name: secrets
mountPath: /config/secrets.yaml
subPath: secrets.yaml
readOnly: true
env:
- name: CONFIG_PATH
value: "/config/config.yaml"
- name: SECRETS_PATH
value: "/config/secrets.yaml"
resources:
requests:
memory: "256Mi"
cpu: "100m"
limits:
memory: "512Mi"
cpu: "500m"
livenessProbe:
httpGet:
path: /health
port: http
initialDelaySeconds: 10
periodSeconds: 30
readinessProbe:
httpGet:
path: /health
port: http
initialDelaySeconds: 5
periodSeconds: 10

View File

@@ -14,4 +14,12 @@ spec:
rules:
- host: dexorder.ai
http:
paths: []
paths:
# Web application at root
- path: /
pathType: Prefix
backend:
service:
name: ai-web
port:
number: 5173

View File

@@ -16,11 +16,11 @@ resources:
- agent-quotas.yaml
# Network isolation policies
- network-policies.yaml
# Gateway service (uncomment when ready)
# - gateway.yaml
# Gateway service
- gateway.yaml
- gateway-ingress.yaml
# Example agent deployment (for reference, not applied by default)
# - agent-deployment-example.yaml
# Services (uncomment as needed)
# - backend.yaml
# - web.yaml
# - ingress.yaml
# Services
- web.yaml
- ingress.yaml

View File

@@ -1,17 +1,9 @@
# Namespace definitions for dexorder AI platform
# - dexorder-system: gateway, flink, kafka, and other infrastructure
# - default: gateway, web, and infrastructure services
# - dexorder-agents: user agent containers (isolated, restricted)
---
apiVersion: v1
kind: Namespace
metadata:
name: dexorder-system
labels:
app.kubernetes.io/part-of: dexorder
dexorder.io/type: system
---
apiVersion: v1
kind: Namespace
metadata:
name: dexorder-agents
labels:

View File

@@ -28,10 +28,7 @@ spec:
- Ingress
ingress:
- from:
- namespaceSelector:
matchLabels:
dexorder.io/type: system
podSelector:
- podSelector:
matchLabels:
app: gateway
ports:
@@ -64,17 +61,14 @@ spec:
port: 53
- protocol: TCP
port: 53
# Gateway in system namespace (for callbacks)
# Gateway (for callbacks)
- to:
- namespaceSelector:
matchLabels:
dexorder.io/type: system
podSelector:
- podSelector:
matchLabels:
app: gateway
ports:
- protocol: TCP
port: 8080
port: 3000
# Kafka/Redpanda for data subscriptions
- to:
- namespaceSelector:
@@ -99,12 +93,11 @@ spec:
- protocol: TCP
port: 443
---
# System namespace: allow ingress from agents
# Default namespace: allow ingress from agents to gateway
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-agent-callbacks
namespace: dexorder-system
spec:
podSelector:
matchLabels:
@@ -118,4 +111,4 @@ spec:
dexorder.io/type: agents
ports:
- protocol: TCP
port: 8080
port: 3000

View File

@@ -32,7 +32,7 @@ spec:
ports:
- containerPort: 5173
env:
- name: VITE_BASE_PATH
value: "/cryptochimp/"
- name: VITE_GATEWAY_URL
value: "https://dexorder.ai/api"
- name: VITE_WS_URL
value: "wss://dexorder.ai/ws"

View File

@@ -0,0 +1,66 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: gateway-config
data:
config.yaml: |
# Gateway Configuration
# Server configuration
server:
port: 3000
host: 0.0.0.0
log_level: debug
cors_origin: "*"
base_url: http://dexorder.local
trusted_origins:
- http://dexorder.local
- http://localhost:5173
- ws://dexorder.local
# Database
database:
url: postgresql://postgres:password@postgres:5432/iceberg
# Default model (if user has no preference)
defaults:
model_provider: anthropic
model: claude-3-5-sonnet-20241022
# Kubernetes configuration
kubernetes:
namespace: dexorder-agents
in_cluster: true
agent_image: ghcr.io/dexorder/agent:latest
sidecar_image: lifecycle-sidecar:latest
storage_class: standard
# DragonflyDB (Redis-compatible, for hot storage and session management)
redis:
url: redis://dragonfly:6379
# Qdrant (for RAG vector search)
qdrant:
url: http://qdrant:6333
collection: gateway_memory
# Iceberg (for durable storage via REST catalog)
iceberg:
catalog_uri: http://iceberg-catalog:8181
namespace: gateway
s3_endpoint: http://minio:9000
# Event router (ZeroMQ)
events:
router_bind: tcp://*:5571
# Embeddings (for RAG vector search)
# Ollama runs in the same container as the gateway (see gateway/Dockerfile)
embedding:
provider: ollama
model: all-minilm
ollama_url: http://localhost:11434
# Email service configuration
email:
from_address: noreply@dexorder.com

View File

@@ -0,0 +1,15 @@
# Gateway dev overrides - use local image
apiVersion: apps/v1
kind: Deployment
metadata:
name: gateway
spec:
template:
spec:
containers:
- name: gateway
image: dexorder/gateway:latest
imagePullPolicy: Never
env:
- name: NODE_OPTIONS
value: "--trace-deprecation"

View File

@@ -0,0 +1,19 @@
---
# Separate ingress for health endpoint without rewrite
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: gateway-health-ingress
spec:
ingressClassName: nginx
rules:
- host: dexorder.local
http:
paths:
- path: /health
pathType: Exact
backend:
service:
name: gateway
port:
number: 3000

View File

@@ -0,0 +1,27 @@
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: gateway-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$1
# Enable WebSocket support
nginx.ingress.kubernetes.io/websocket-services: gateway
nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
nginx.ingress.kubernetes.io/proxy-send-timeout: "3600"
spec:
ingressClassName: nginx
# Remove TLS for dev
tls: []
rules:
- host: dexorder.local
http:
paths:
# Gateway API routes - strip /api prefix
- path: /api/(.*)
pathType: ImplementationSpecific
backend:
service:
name: gateway
port:
number: 3000

View File

@@ -1,4 +1,112 @@
---
# DragonflyDB (Redis-compatible in-memory datastore)
apiVersion: v1
kind: Service
metadata:
name: dragonfly
spec:
selector:
app: dragonfly
ports:
- protocol: TCP
port: 6379
targetPort: 6379
type: ClusterIP
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: dragonfly
spec:
replicas: 1
selector:
matchLabels:
app: dragonfly
template:
metadata:
labels:
app: dragonfly
spec:
containers:
- name: dragonfly
image: docker.dragonflydb.io/dragonflydb/dragonfly:latest
ports:
- containerPort: 6379
name: dragonfly
args:
- --logtostderr
- --alsologtostderr=false
- --cache_mode=true
resources:
requests:
memory: "256Mi"
cpu: "100m"
limits:
memory: "512Mi"
cpu: "500m"
---
# Qdrant (Vector database for RAG)
apiVersion: v1
kind: Service
metadata:
name: qdrant
spec:
selector:
app: qdrant
ports:
- name: http
protocol: TCP
port: 6333
targetPort: 6333
- name: grpc
protocol: TCP
port: 6334
targetPort: 6334
type: ClusterIP
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: qdrant
spec:
serviceName: qdrant
replicas: 1
selector:
matchLabels:
app: qdrant
template:
metadata:
labels:
app: qdrant
spec:
containers:
- name: qdrant
image: qdrant/qdrant:latest
ports:
- containerPort: 6333
name: http
- containerPort: 6334
name: grpc
resources:
requests:
memory: "512Mi"
cpu: "200m"
limits:
memory: "1Gi"
cpu: "1000m"
volumeMounts:
- name: qdrant-data
mountPath: /qdrant/storage
volumeClaimTemplates:
- metadata:
name: qdrant-data
spec:
accessModes: ["ReadWriteOnce"]
storageClassName: dev-ephemeral
resources:
requests:
storage: 10Gi
---
# Kafka (KRaft mode - no Zookeeper needed)
# Using apache/kafka:3.9.0 instead of confluentinc/cp-kafka because:
# - cp-kafka's entrypoint script has issues with KRaft configuration
@@ -74,6 +182,7 @@ spec:
name: kafka-data
spec:
accessModes: ["ReadWriteOnce"]
storageClassName: dev-ephemeral
resources:
requests:
storage: 5Gi
@@ -130,6 +239,7 @@ spec:
name: postgres-data
spec:
accessModes: ["ReadWriteOnce"]
storageClassName: dev-ephemeral
resources:
requests:
storage: 2Gi
@@ -200,6 +310,7 @@ spec:
name: minio-data
spec:
accessModes: ["ReadWriteOnce"]
storageClassName: dev-ephemeral
resources:
requests:
storage: 10Gi

View File

@@ -8,4 +8,12 @@ spec:
rules:
- host: dexorder.local
http:
paths: []
paths:
# Web application at root
- path: /
pathType: Prefix
backend:
service:
name: ai-web
port:
number: 5173

View File

@@ -1,13 +1,13 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
# Note: namespaces are defined in base; workloads go to dexorder-system
namespace: dexorder-system
# Base resources (includes security policies)
resources:
- ../base
- infrastructure.yaml
- storage-class.yaml
- configs/gateway-config.yaml
- gateway-health-ingress.yaml
# Dev-specific patches
patches:
@@ -15,6 +15,14 @@ patches:
- path: agent-quotas-patch.yaml
# Allow local registry images
- path: admission-policy-patch.yaml
# Web environment variables for dev
- path: web-dev-patch.yaml
# Web ingress for dev (no TLS, dexorder.local)
- path: web-ingress-patch.yaml
# Gateway dev overrides (use local image)
- path: gateway-dev-patch.yaml
# Gateway ingress for dev (no TLS, dexorder.local)
- path: gateway-ingress-patch.yaml
# ConfigMaps for service configs
configMapGenerator:
@@ -34,3 +42,24 @@ secretGenerator: []
generatorOptions:
disableNameSuffixHash: true

View File

@@ -0,0 +1,13 @@
---
# Development-specific StorageClass with auto-deletion
# This ensures PVCs and PVs are automatically cleaned up when released
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: dev-ephemeral
labels:
environment: development
provisioner: k8s.io/minikube-hostpath
reclaimPolicy: Delete
volumeBindingMode: Immediate
allowVolumeExpansion: false

View File

@@ -0,0 +1,17 @@
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: ai-web
spec:
template:
spec:
containers:
- name: ai-web
image: dexorder/ai-web:latest
imagePullPolicy: Never
env:
- name: VITE_GATEWAY_URL
value: "/api"
- name: VITE_WS_URL
value: "ws://dexorder.local/api/ws/chat"

View File

@@ -0,0 +1,21 @@
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ai-ingress
spec:
ingressClassName: nginx
# Remove TLS for dev
tls: []
rules:
- host: dexorder.local
http:
paths:
# Web application at root
- path: /
pathType: Prefix
backend:
service:
name: ai-web
port:
number: 5173

View File

@@ -0,0 +1,64 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: gateway-config
data:
config.yaml: |
# Gateway Configuration
# Server configuration
server:
port: 3000
host: 0.0.0.0
log_level: info
cors_origin: "https://app.dexorder.com"
base_url: https://api.dexorder.com
trusted_origins:
- https://app.dexorder.com
- https://api.dexorder.com
# Database
database:
url: postgresql://postgres:postgres@postgres:5432/iceberg
# Default model (if user has no preference)
defaults:
model_provider: anthropic
model: claude-3-5-sonnet-20241022
# Kubernetes configuration
kubernetes:
namespace: dexorder-agents
in_cluster: true
agent_image: ghcr.io/dexorder/agent:latest
sidecar_image: ghcr.io/dexorder/lifecycle-sidecar:latest
storage_class: standard
# DragonflyDB (Redis-compatible, for hot storage and session management)
redis:
url: redis://dragonfly:6379
# Qdrant (for RAG vector search)
qdrant:
url: http://qdrant:6333
collection: gateway_memory
# Iceberg (for durable storage via REST catalog)
iceberg:
catalog_uri: http://iceberg-catalog:8181
namespace: gateway
s3_endpoint: http://minio:9000
# Event router (ZeroMQ)
events:
router_bind: tcp://*:5571
# Embeddings (for RAG vector search)
embedding:
provider: ollama
model: all-minilm
ollama_url: http://ollama:11434
# Email service configuration
email:
from_address: noreply@dexorder.com

View File

@@ -1,12 +1,10 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
# Note: namespaces are defined in base; workloads go to dexorder-system
namespace: dexorder-system
# Base resources (includes all security policies)
resources:
- ../base
- configs/gateway-config.yaml
# Production patches
patches:
@@ -18,13 +16,13 @@ patches:
configMapGenerator:
- name: relay-config
files:
- config.yaml=../../configmaps/relay-config.yaml
- config.yaml=configs/relay-config.yaml
- name: ingestor-config
files:
- config.yaml=../../configmaps/ingestor-config.yaml
- config.yaml=configs/ingestor-config.yaml
- name: flink-config
files:
- config.yaml=../../configmaps/flink-config.yaml
- config.yaml=configs/flink-config.yaml
# Secrets (managed via kubectl, not committed)
# These are created by bin/secret-update prod

View File

@@ -39,8 +39,8 @@ spec:
image: dexorder/ai-web:latest
imagePullPolicy: Always
env:
- name: VITE_BASE_PATH
value: "/cryptochimp/"
- name: VITE_GATEWAY_URL
value: "https://dexorder.ai/api"
- name: VITE_WS_URL
value: "wss://dexorder.ai/ws"
resources: