diff --git a/.gitea/workflows/ci.yaml b/.gitea/workflows/ci.yaml index 7a4d787..2e6b603 100644 --- a/.gitea/workflows/ci.yaml +++ b/.gitea/workflows/ci.yaml @@ -673,7 +673,7 @@ jobs: envsubst < k8s/storage-pvc.yaml > /tmp/storage-pvc.yaml fi - envsubst < k8s/backend.yaml > /tmp/backend.yaml + envsubst < k8s/switchboard.yaml > /tmp/switchboard.yaml envsubst < k8s/middleware-retry.yaml > /tmp/middleware-retry.yaml envsubst < k8s/ingress.yaml > /tmp/ingress.yaml @@ -687,7 +687,7 @@ jobs: echo " ⚠ STORAGE_CLASS not set — file storage disabled" fi - kubectl apply -f /tmp/backend.yaml + kubectl apply -f /tmp/switchboard.yaml # Traefik retry middleware (v0.28.8) — requires RBAC for traefik.io CRDs. # First-time setup: kubectl apply -f k8s/rbac-traefik.yaml (cluster admin) @@ -718,14 +718,14 @@ jobs: SUFFIX: ${{ steps.setup.outputs.DEPLOY_SUFFIX }} ENV: ${{ steps.setup.outputs.ENVIRONMENT }} run: | - kubectl rollout restart deployment/switchboard-be${SUFFIX} -n ${NAMESPACE} - kubectl rollout status deployment/switchboard-be${SUFFIX} -n ${NAMESPACE} --timeout=180s + kubectl rollout restart deployment/switchboard${SUFFIX} -n ${NAMESPACE} + kubectl rollout status deployment/switchboard${SUFFIX} -n ${NAMESPACE} --timeout=180s echo "" echo "━━━ Pod Status ━━━" kubectl get pods -n ${NAMESPACE} -l app=switchboard,env=${ENV} - READY=$(kubectl get deployment switchboard-be${SUFFIX} -n ${NAMESPACE} -o jsonpath='{.status.readyReplicas}') + READY=$(kubectl get deployment switchboard${SUFFIX} -n ${NAMESPACE} -o jsonpath='{.status.readyReplicas}') if [[ "${READY:-0}" -gt 0 ]]; then echo "✅ Healthy: ${READY} pods ready" diff --git a/CHANGELOG.md b/CHANGELOG.md index 9474f3f..4140ba6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,14 @@ Forked from chat-switchboard v0.38.5. Gutted to a pure extension platform. filters, retention, workspace - **29 handler files**, 6 test files, ~44K lines total +### Fixed + +- CI deploy: k8s resource quantity vars (`BE_MEMORY_REQUEST` → `MEMORY_REQUEST`) + aligned with CI workflow outputs — `envsubst` was producing empty strings +- CI deploy: image var (`BE_IMAGE` → `IMAGE`) — caused `InvalidImageName` in pods +- CI rollout: deployment name (`switchboard` → `switchboard-be`) — rollout + verification was looking for wrong deployment name + ### Changed - Module renamed: `chat-switchboard` → `switchboard-core` diff --git a/ROADMAP.md b/ROADMAP.md index 615547c..d3e7933 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -6,6 +6,16 @@ Fork of chat-switchboard, gutted to a pure extension platform. All AI/chat features removed from the kernel. What remains is the minimum viable platform that extensions build on. +### Retained kernel capabilities + +- **Auth**: builtin (simple), mTLS, OIDC +- **Identity**: users, teams, groups, permissions (RBAC) +- **Packages**: surfaces, extensions, libraries, workflows +- **Starlark sandbox**: capability-gated modules +- **Storage**: object storage (PVC, S3), ext_data tables +- **Realtime**: WebSocket hub, presence, multi-replica HA +- **Ops**: audit log, notifications, maintenance goroutine + ### Phase 0 (in progress) | Step | Status | Description | @@ -18,8 +28,8 @@ platform that extensions build on. | 6. Fix tests | ✅ | 8 test packages pass, ~12K stale test lines pruned | | 7. Frontend gut | ✅ | Shell + SDK only, 50+ files of chat/notes/projects code removed | | 8. New ICD | 🔧 | Stub in place, full kernel-only spec TBD | -| 9. CI/CD + Dockerfile | ✅ | Single unified image, FE/BE split removed, DB names updated | -| 10. Smoke test + tag | ⬜ | Deploy, verify, tag v0.1.0 | +| 9. CI/CD + Dockerfile | ✅ | Single unified image, FE/BE split removed, DB names updated, k8s var alignment fixes (resource quantities, image name, rollout deployment name) | +| 10. Smoke test + tag | 🔧 | Deploy passes CI, verify health + ingress routing, tag v0.1.0 | ## v0.2.0 — SDK & Triggers @@ -33,6 +43,14 @@ SDK stabilization, and the first rebuilt extension (tasks). - **Theme tokens** exposed to extensions - **Task extension**: first proof-of-concept — full task system rebuilt as a Starlark extension using triggers + ext_data + notifications +- **Settings override model**: RBAC controls scope auth (admin → global, + team-admin → team, user → personal). `user_overridable` flag on each setting + controls whether lower scopes can override higher. Resolution order: + user → team → global (first non-null wins, walking up if overridable). + Extension manifests declare `user_overridable` per setting key. +- **Default surface routing**: `/` redirects to configurable default surface. + No surfaces installed → admin surface is default. First surface installed + becomes default. Changeable in admin settings. ## v0.3.0 — Editor Surface diff --git a/k8s/ingress.yaml b/k8s/ingress.yaml index 59df944..4bb5c8a 100644 --- a/k8s/ingress.yaml +++ b/k8s/ingress.yaml @@ -13,7 +13,7 @@ # # BASE_PATH is empty for prod, "/test" or "/dev" for others. # Backend handles BASE_PATH via r.Group(cfg.BasePath). -# Frontend entrypoint injects BASE_PATH into nginx + HTML. +# Single unified image serves both API and static assets. # ============================================ apiVersion: networking.k8s.io/v1 kind: Ingress @@ -36,36 +36,11 @@ spec: - host: "${DEPLOY_HOST}" http: paths: - # API routes → backend - - path: ${BASE_PATH}/api - pathType: Prefix - backend: - service: - name: switchboard-be${DEPLOY_SUFFIX} - port: - number: 8080 - # Health check → backend - - path: ${BASE_PATH}/health - pathType: Prefix - backend: - service: - name: switchboard-be${DEPLOY_SUFFIX} - port: - number: 8080 - # WebSocket → backend (must be Prefix, not Exact — Traefik's Exact - # doesn't reliably win over Prefix rules in the same Ingress resource) - - path: ${BASE_PATH}/ws - pathType: Prefix - backend: - service: - name: switchboard-be${DEPLOY_SUFFIX} - port: - number: 8080 - # Everything else under this prefix → frontend + # All traffic → switchboard (unified image) - path: ${BASE_PATH}/ pathType: Prefix backend: service: - name: switchboard-fe${DEPLOY_SUFFIX} + name: switchboard${DEPLOY_SUFFIX} port: - number: 80 + number: 8080 diff --git a/k8s/switchboard.yaml b/k8s/switchboard.yaml index 9c65adb..d3804e9 100644 --- a/k8s/switchboard.yaml +++ b/k8s/switchboard.yaml @@ -1,6 +1,6 @@ -# k8s/backend.yaml +# k8s/switchboard.yaml # ============================================ -# Switchboard Core - Backend Deployment +# Switchboard Core - Deployment # ============================================ # Secrets: # switchboard-db-credentials - POSTGRES_USER, POSTGRES_PASSWORD @@ -16,8 +16,6 @@ # STORAGE_CLASS - StorageClass for PVC (e.g. "cephfs") # STORAGE_SIZE - PVC size (e.g. "10Gi" for PVC, "1Gi" for S3) # STORAGE_BACKEND - "pvc" or "s3" (default: "pvc") -# EXTRACTION_CONCURRENCY - Max concurrent extractions (default "3") -# EXTRACTOR_IMAGE - Sidecar image (LibreOffice headless) # # S3 secrets (Gitea Secrets — only when STORAGE_BACKEND=s3): # S3_ENDPOINT - e.g. "http://minio:9000" or Ceph RGW URL @@ -32,28 +30,25 @@ apiVersion: apps/v1 kind: Deployment metadata: - name: switchboard-be${DEPLOY_SUFFIX} + name: switchboard${DEPLOY_SUFFIX} namespace: ${NAMESPACE} labels: app: switchboard - component: backend env: ${ENVIRONMENT} spec: - replicas: ${BE_REPLICAS} + replicas: ${REPLICAS} selector: matchLabels: app: switchboard - component: backend env: ${ENVIRONMENT} template: metadata: labels: app: switchboard - component: backend env: ${ENVIRONMENT} spec: containers: - - name: backend + - name: switchboard image: ${IMAGE}:${IMAGE_TAG} imagePullPolicy: Always ports: @@ -121,10 +116,6 @@ spec: value: "${STORAGE_BACKEND}" - name: STORAGE_PATH value: "/data/storage" - - name: EXTRACTION_MODE - value: "sidecar" - - name: EXTRACTION_CONCURRENCY - value: "${EXTRACTION_CONCURRENCY}" # S3 storage (optional — only used when STORAGE_BACKEND=s3) - name: S3_ENDPOINT valueFrom: @@ -191,29 +182,6 @@ spec: timeoutSeconds: 5 failureThreshold: 3 - # Extractor sidecar (v0.12.0 Phase 2): - # Uncomment when switchboard-extractor image is built. - # See DESIGN-0.12.0.md — Phase 2: Extraction Pipeline. - # - # - name: extractor - # image: ${EXTRACTOR_IMAGE}:${IMAGE_TAG} - # imagePullPolicy: Always - # env: - # - name: STORAGE_PATH - # value: "/data/storage" - # - name: EXTRACTION_CONCURRENCY - # value: "${EXTRACTION_CONCURRENCY}" - # volumeMounts: - # - name: storage - # mountPath: /data/storage - # resources: - # requests: - # memory: "256Mi" - # cpu: "100m" - # limits: - # memory: "1Gi" - # cpu: "1000m" - volumes: - name: storage persistentVolumeClaim: @@ -222,16 +190,14 @@ spec: apiVersion: v1 kind: Service metadata: - name: switchboard-be${DEPLOY_SUFFIX} + name: switchboard${DEPLOY_SUFFIX} namespace: ${NAMESPACE} labels: app: switchboard - component: backend env: ${ENVIRONMENT} spec: selector: app: switchboard - component: backend env: ${ENVIRONMENT} ports: - protocol: TCP