step 9: single image CI/CD, drop FE/BE split
CI pipeline: replace separate FE + BE image builds with single unified Dockerfile. Remove FE_IMAGE, FE_REPLICAS, FE_* resource vars. Simplify build/push/deploy to single IMAGE. Remove frontend.yaml k8s manifest. Remove provider integration test env vars (PROVIDER, PROVIDER_KEY, VENICE_API_KEY). Remove EXTRACTION_CONCURRENCY. Delete server/Dockerfile (backend-only image, superseded by root Dockerfile). Delete k8s/frontend.yaml (no separate FE deployment). Update ROADMAP: steps 5-7 and 9 marked complete. Step 8 (ICD) partial. Step 10 (smoke test + tag) is all that remains for v0.1.0. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -2,8 +2,8 @@
|
|||||||
# ============================================
|
# ============================================
|
||||||
# Switchboard Core - CI/CD Pipeline (v0.17.3)
|
# Switchboard Core - CI/CD Pipeline (v0.17.3)
|
||||||
# ============================================
|
# ============================================
|
||||||
# Cluster deployments use SEPARATE FE + BE images.
|
# Single unified image (Go backend + nginx frontend).
|
||||||
# Unified image is for Docker Hub only (docker-compose use).
|
# v0.1.0: Dropped FE/BE image split per ROADMAP design decision.
|
||||||
#
|
#
|
||||||
# Pipeline:
|
# Pipeline:
|
||||||
# 0. Detect changes (path-based gating for all downstream jobs)
|
# 0. Detect changes (path-based gating for all downstream jobs)
|
||||||
@@ -88,8 +88,7 @@ env:
|
|||||||
CERT_ISSUER: ${{ vars.CERT_ISSUER_PROD || 'letsencrypt-prod' }}
|
CERT_ISSUER: ${{ vars.CERT_ISSUER_PROD || 'letsencrypt-prod' }}
|
||||||
POSTGRES_HOST: ${{ vars.POSTGRES_HOST || 'postgres-primary.postgres.svc.cluster.local' }}
|
POSTGRES_HOST: ${{ vars.POSTGRES_HOST || 'postgres-primary.postgres.svc.cluster.local' }}
|
||||||
POSTGRES_PORT: ${{ vars.POSTGRES_PORT || '5432' }}
|
POSTGRES_PORT: ${{ vars.POSTGRES_PORT || '5432' }}
|
||||||
FE_IMAGE: ${{ vars.REGISTRY }}/xcaliber/switchboard-fe
|
IMAGE: ${{ vars.REGISTRY }}/switchboard/core
|
||||||
BE_IMAGE: ${{ vars.REGISTRY }}/xcaliber/switchboard-be
|
|
||||||
DOCKERHUB_IMAGE: ${{ vars.DOCKERHUB_IMAGE || 'gobha/switchboard-core' }}
|
DOCKERHUB_IMAGE: ${{ vars.DOCKERHUB_IMAGE || 'gobha/switchboard-core' }}
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
@@ -297,12 +296,6 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
GOPRIVATE: git.gobha.me/*
|
GOPRIVATE: git.gobha.me/*
|
||||||
GONOSUMCHECK: git.gobha.me/*
|
GONOSUMCHECK: git.gobha.me/*
|
||||||
# Generic provider config for live integration tests
|
|
||||||
PROVIDER: ${{ vars.PROVIDER }}
|
|
||||||
PROVIDER_KEY: ${{ secrets.PROVIDER_KEY }}
|
|
||||||
PROVIDER_URL: ${{ vars.PROVIDER_URL }}
|
|
||||||
# Legacy compat: VENICE_API_KEY still works if PROVIDER_KEY is not set
|
|
||||||
VENICE_API_KEY: ${{ secrets.VENICE_API_KEY }}
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
@@ -415,16 +408,11 @@ jobs:
|
|||||||
echo "DEPLOY_SUFFIX=-dev" >> "$GITHUB_OUTPUT"
|
echo "DEPLOY_SUFFIX=-dev" >> "$GITHUB_OUTPUT"
|
||||||
echo "DB_NAME=switchboard_core_dev" >> "$GITHUB_OUTPUT"
|
echo "DB_NAME=switchboard_core_dev" >> "$GITHUB_OUTPUT"
|
||||||
echo "DB_WIPE=true" >> "$GITHUB_OUTPUT"
|
echo "DB_WIPE=true" >> "$GITHUB_OUTPUT"
|
||||||
echo "FE_REPLICAS=1" >> "$GITHUB_OUTPUT"
|
echo "REPLICAS=1" >> "$GITHUB_OUTPUT"
|
||||||
echo "BE_REPLICAS=1" >> "$GITHUB_OUTPUT"
|
echo "MEMORY_REQUEST=256Mi" >> "$GITHUB_OUTPUT"
|
||||||
echo "FE_MEMORY_REQUEST=64Mi" >> "$GITHUB_OUTPUT"
|
echo "MEMORY_LIMIT=512Mi" >> "$GITHUB_OUTPUT"
|
||||||
echo "FE_MEMORY_LIMIT=128Mi" >> "$GITHUB_OUTPUT"
|
echo "CPU_REQUEST=50m" >> "$GITHUB_OUTPUT"
|
||||||
echo "FE_CPU_REQUEST=25m" >> "$GITHUB_OUTPUT"
|
echo "CPU_LIMIT=250m" >> "$GITHUB_OUTPUT"
|
||||||
echo "FE_CPU_LIMIT=100m" >> "$GITHUB_OUTPUT"
|
|
||||||
echo "BE_MEMORY_REQUEST=256Mi" >> "$GITHUB_OUTPUT"
|
|
||||||
echo "BE_MEMORY_LIMIT=512Mi" >> "$GITHUB_OUTPUT"
|
|
||||||
echo "BE_CPU_REQUEST=50m" >> "$GITHUB_OUTPUT"
|
|
||||||
echo "BE_CPU_LIMIT=250m" >> "$GITHUB_OUTPUT"
|
|
||||||
echo "env_label=dev (PR #${{ gitea.event.pull_request.number }})" >> "$GITHUB_OUTPUT"
|
echo "env_label=dev (PR #${{ gitea.event.pull_request.number }})" >> "$GITHUB_OUTPUT"
|
||||||
elif [[ "${{ gitea.ref }}" == refs/tags/v* ]]; then
|
elif [[ "${{ gitea.ref }}" == refs/tags/v* ]]; then
|
||||||
VERSION="${{ gitea.ref_name }}"
|
VERSION="${{ gitea.ref_name }}"
|
||||||
@@ -436,16 +424,11 @@ jobs:
|
|||||||
echo "DEPLOY_SUFFIX=" >> "$GITHUB_OUTPUT"
|
echo "DEPLOY_SUFFIX=" >> "$GITHUB_OUTPUT"
|
||||||
echo "DB_NAME=switchboard_core" >> "$GITHUB_OUTPUT"
|
echo "DB_NAME=switchboard_core" >> "$GITHUB_OUTPUT"
|
||||||
echo "DB_WIPE=false" >> "$GITHUB_OUTPUT"
|
echo "DB_WIPE=false" >> "$GITHUB_OUTPUT"
|
||||||
echo "FE_REPLICAS=2" >> "$GITHUB_OUTPUT"
|
echo "REPLICAS=2" >> "$GITHUB_OUTPUT"
|
||||||
echo "BE_REPLICAS=2" >> "$GITHUB_OUTPUT"
|
echo "MEMORY_REQUEST=256Mi" >> "$GITHUB_OUTPUT"
|
||||||
echo "FE_MEMORY_REQUEST=64Mi" >> "$GITHUB_OUTPUT"
|
echo "MEMORY_LIMIT=512Mi" >> "$GITHUB_OUTPUT"
|
||||||
echo "FE_MEMORY_LIMIT=128Mi" >> "$GITHUB_OUTPUT"
|
echo "CPU_REQUEST=100m" >> "$GITHUB_OUTPUT"
|
||||||
echo "FE_CPU_REQUEST=50m" >> "$GITHUB_OUTPUT"
|
echo "CPU_LIMIT=500m" >> "$GITHUB_OUTPUT"
|
||||||
echo "FE_CPU_LIMIT=200m" >> "$GITHUB_OUTPUT"
|
|
||||||
echo "BE_MEMORY_REQUEST=256Mi" >> "$GITHUB_OUTPUT"
|
|
||||||
echo "BE_MEMORY_LIMIT=512Mi" >> "$GITHUB_OUTPUT"
|
|
||||||
echo "BE_CPU_REQUEST=100m" >> "$GITHUB_OUTPUT"
|
|
||||||
echo "BE_CPU_LIMIT=500m" >> "$GITHUB_OUTPUT"
|
|
||||||
echo "is_release=true" >> "$GITHUB_OUTPUT"
|
echo "is_release=true" >> "$GITHUB_OUTPUT"
|
||||||
echo "env_label=production (${VERSION})" >> "$GITHUB_OUTPUT"
|
echo "env_label=production (${VERSION})" >> "$GITHUB_OUTPUT"
|
||||||
else
|
else
|
||||||
@@ -456,16 +439,11 @@ jobs:
|
|||||||
echo "DEPLOY_SUFFIX=-test" >> "$GITHUB_OUTPUT"
|
echo "DEPLOY_SUFFIX=-test" >> "$GITHUB_OUTPUT"
|
||||||
echo "DB_NAME=switchboard_core_test" >> "$GITHUB_OUTPUT"
|
echo "DB_NAME=switchboard_core_test" >> "$GITHUB_OUTPUT"
|
||||||
echo "DB_WIPE=false" >> "$GITHUB_OUTPUT"
|
echo "DB_WIPE=false" >> "$GITHUB_OUTPUT"
|
||||||
echo "FE_REPLICAS=1" >> "$GITHUB_OUTPUT"
|
echo "REPLICAS=1" >> "$GITHUB_OUTPUT"
|
||||||
echo "BE_REPLICAS=1" >> "$GITHUB_OUTPUT"
|
echo "MEMORY_REQUEST=256Mi" >> "$GITHUB_OUTPUT"
|
||||||
echo "FE_MEMORY_REQUEST=64Mi" >> "$GITHUB_OUTPUT"
|
echo "MEMORY_LIMIT=512Mi" >> "$GITHUB_OUTPUT"
|
||||||
echo "FE_MEMORY_LIMIT=128Mi" >> "$GITHUB_OUTPUT"
|
echo "CPU_REQUEST=50m" >> "$GITHUB_OUTPUT"
|
||||||
echo "FE_CPU_REQUEST=25m" >> "$GITHUB_OUTPUT"
|
echo "CPU_LIMIT=250m" >> "$GITHUB_OUTPUT"
|
||||||
echo "FE_CPU_LIMIT=100m" >> "$GITHUB_OUTPUT"
|
|
||||||
echo "BE_MEMORY_REQUEST=256Mi" >> "$GITHUB_OUTPUT"
|
|
||||||
echo "BE_MEMORY_LIMIT=512Mi" >> "$GITHUB_OUTPUT"
|
|
||||||
echo "BE_CPU_REQUEST=50m" >> "$GITHUB_OUTPUT"
|
|
||||||
echo "BE_CPU_LIMIT=250m" >> "$GITHUB_OUTPUT"
|
|
||||||
echo "env_label=test (main)" >> "$GITHUB_OUTPUT"
|
echo "env_label=test (main)" >> "$GITHUB_OUTPUT"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -577,45 +555,33 @@ jobs:
|
|||||||
SQL
|
SQL
|
||||||
echo "✓ Dev wipe complete — backend will rebuild schema on startup"
|
echo "✓ Dev wipe complete — backend will rebuild schema on startup"
|
||||||
|
|
||||||
# ── Build Backend Image ──────────────────────
|
# ── Build Unified Image ──────────────────────
|
||||||
- name: Build backend image
|
- name: Build image
|
||||||
run: |
|
run: |
|
||||||
docker build -f server/Dockerfile \
|
docker build -f Dockerfile \
|
||||||
-t ${BE_IMAGE}:${{ steps.setup.outputs.IMAGE_TAG }} \
|
-t ${IMAGE}:${{ steps.setup.outputs.IMAGE_TAG }} \
|
||||||
.
|
|
||||||
|
|
||||||
# ── Build Frontend Image ─────────────────────
|
|
||||||
- name: Build frontend image
|
|
||||||
run: |
|
|
||||||
docker build -f Dockerfile.frontend \
|
|
||||||
-t ${FE_IMAGE}:${{ steps.setup.outputs.IMAGE_TAG }} \
|
|
||||||
.
|
.
|
||||||
|
|
||||||
# ── Tag release versions ─────────────────────
|
# ── Tag release versions ─────────────────────
|
||||||
- name: Tag release versions
|
- name: Tag release versions
|
||||||
if: steps.setup.outputs.EXTRA_TAG != ''
|
if: steps.setup.outputs.EXTRA_TAG != ''
|
||||||
run: |
|
run: |
|
||||||
docker tag ${BE_IMAGE}:${{ steps.setup.outputs.IMAGE_TAG }} ${BE_IMAGE}:${{ steps.setup.outputs.EXTRA_TAG }}
|
docker tag ${IMAGE}:${{ steps.setup.outputs.IMAGE_TAG }} ${IMAGE}:${{ steps.setup.outputs.EXTRA_TAG }}
|
||||||
docker tag ${FE_IMAGE}:${{ steps.setup.outputs.IMAGE_TAG }} ${FE_IMAGE}:${{ steps.setup.outputs.EXTRA_TAG }}
|
|
||||||
|
|
||||||
# ── Push to Internal Registry ────────────────
|
# ── Push to Internal Registry ────────────────
|
||||||
- name: Push images
|
- name: Push image
|
||||||
run: |
|
run: |
|
||||||
docker push ${BE_IMAGE}:${{ steps.setup.outputs.IMAGE_TAG }}
|
docker push ${IMAGE}:${{ steps.setup.outputs.IMAGE_TAG }}
|
||||||
docker push ${FE_IMAGE}:${{ steps.setup.outputs.IMAGE_TAG }}
|
|
||||||
if [[ -n "${{ steps.setup.outputs.EXTRA_TAG }}" ]]; then
|
if [[ -n "${{ steps.setup.outputs.EXTRA_TAG }}" ]]; then
|
||||||
docker push ${BE_IMAGE}:${{ steps.setup.outputs.EXTRA_TAG }}
|
docker push ${IMAGE}:${{ steps.setup.outputs.EXTRA_TAG }}
|
||||||
docker push ${FE_IMAGE}:${{ steps.setup.outputs.EXTRA_TAG }}
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# ── Build + Push Unified to Docker Hub (release only) ──
|
# ── Push to Docker Hub (release only) ────────
|
||||||
- name: Build and push unified image
|
- name: Push to Docker Hub
|
||||||
if: steps.setup.outputs.is_release == 'true'
|
if: steps.setup.outputs.is_release == 'true'
|
||||||
run: |
|
run: |
|
||||||
docker build -f Dockerfile \
|
docker tag ${IMAGE}:${{ steps.setup.outputs.IMAGE_TAG }} ${DOCKERHUB_IMAGE}:latest
|
||||||
-t ${DOCKERHUB_IMAGE}:latest \
|
docker tag ${IMAGE}:${{ steps.setup.outputs.IMAGE_TAG }} ${DOCKERHUB_IMAGE}:${{ steps.setup.outputs.EXTRA_TAG }}
|
||||||
-t ${DOCKERHUB_IMAGE}:${{ steps.setup.outputs.EXTRA_TAG }} \
|
|
||||||
.
|
|
||||||
if [[ -n "${{ secrets.DOCKERHUB_TOKEN }}" ]]; then
|
if [[ -n "${{ secrets.DOCKERHUB_TOKEN }}" ]]; then
|
||||||
echo "${{ secrets.DOCKERHUB_TOKEN }}" | \
|
echo "${{ secrets.DOCKERHUB_TOKEN }}" | \
|
||||||
docker login -u "${{ secrets.DOCKERHUB_USERNAME }}" --password-stdin
|
docker login -u "${{ secrets.DOCKERHUB_USERNAME }}" --password-stdin
|
||||||
@@ -692,21 +658,15 @@ jobs:
|
|||||||
DEPLOY_HOST: ${{ steps.setup.outputs.DEPLOY_HOST }}
|
DEPLOY_HOST: ${{ steps.setup.outputs.DEPLOY_HOST }}
|
||||||
BASE_PATH: ${{ steps.setup.outputs.BASE_PATH }}
|
BASE_PATH: ${{ steps.setup.outputs.BASE_PATH }}
|
||||||
DB_NAME: ${{ steps.setup.outputs.DB_NAME }}
|
DB_NAME: ${{ steps.setup.outputs.DB_NAME }}
|
||||||
FE_REPLICAS: ${{ steps.setup.outputs.FE_REPLICAS }}
|
REPLICAS: ${{ steps.setup.outputs.REPLICAS }}
|
||||||
BE_REPLICAS: ${{ steps.setup.outputs.BE_REPLICAS }}
|
MEMORY_REQUEST: ${{ steps.setup.outputs.MEMORY_REQUEST }}
|
||||||
FE_MEMORY_REQUEST: ${{ steps.setup.outputs.FE_MEMORY_REQUEST }}
|
MEMORY_LIMIT: ${{ steps.setup.outputs.MEMORY_LIMIT }}
|
||||||
FE_MEMORY_LIMIT: ${{ steps.setup.outputs.FE_MEMORY_LIMIT }}
|
CPU_REQUEST: ${{ steps.setup.outputs.CPU_REQUEST }}
|
||||||
FE_CPU_REQUEST: ${{ steps.setup.outputs.FE_CPU_REQUEST }}
|
CPU_LIMIT: ${{ steps.setup.outputs.CPU_LIMIT }}
|
||||||
FE_CPU_LIMIT: ${{ steps.setup.outputs.FE_CPU_LIMIT }}
|
|
||||||
BE_MEMORY_REQUEST: ${{ steps.setup.outputs.BE_MEMORY_REQUEST }}
|
|
||||||
BE_MEMORY_LIMIT: ${{ steps.setup.outputs.BE_MEMORY_LIMIT }}
|
|
||||||
BE_CPU_REQUEST: ${{ steps.setup.outputs.BE_CPU_REQUEST }}
|
|
||||||
BE_CPU_LIMIT: ${{ steps.setup.outputs.BE_CPU_LIMIT }}
|
|
||||||
# Storage (v0.12.0+)
|
# Storage (v0.12.0+)
|
||||||
STORAGE_CLASS: ${{ vars.STORAGE_CLASS }}
|
STORAGE_CLASS: ${{ vars.STORAGE_CLASS }}
|
||||||
STORAGE_SIZE: ${{ vars.STORAGE_SIZE || '10Gi' }}
|
STORAGE_SIZE: ${{ vars.STORAGE_SIZE || '10Gi' }}
|
||||||
STORAGE_BACKEND: ${{ vars.STORAGE_BACKEND || 'pvc' }}
|
STORAGE_BACKEND: ${{ vars.STORAGE_BACKEND || 'pvc' }}
|
||||||
EXTRACTION_CONCURRENCY: ${{ vars.EXTRACTION_CONCURRENCY || '3' }}
|
|
||||||
run: |
|
run: |
|
||||||
# Render PVC first (must exist before backend references it)
|
# Render PVC first (must exist before backend references it)
|
||||||
if [[ -n "${STORAGE_CLASS}" ]]; then
|
if [[ -n "${STORAGE_CLASS}" ]]; then
|
||||||
@@ -714,7 +674,6 @@ jobs:
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
envsubst < k8s/backend.yaml > /tmp/backend.yaml
|
envsubst < k8s/backend.yaml > /tmp/backend.yaml
|
||||||
envsubst < k8s/frontend.yaml > /tmp/frontend.yaml
|
|
||||||
envsubst < k8s/middleware-retry.yaml > /tmp/middleware-retry.yaml
|
envsubst < k8s/middleware-retry.yaml > /tmp/middleware-retry.yaml
|
||||||
envsubst < k8s/ingress.yaml > /tmp/ingress.yaml
|
envsubst < k8s/ingress.yaml > /tmp/ingress.yaml
|
||||||
|
|
||||||
@@ -729,7 +688,6 @@ jobs:
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
kubectl apply -f /tmp/backend.yaml
|
kubectl apply -f /tmp/backend.yaml
|
||||||
kubectl apply -f /tmp/frontend.yaml
|
|
||||||
|
|
||||||
# Traefik retry middleware (v0.28.8) — requires RBAC for traefik.io CRDs.
|
# Traefik retry middleware (v0.28.8) — requires RBAC for traefik.io CRDs.
|
||||||
# First-time setup: kubectl apply -f k8s/rbac-traefik.yaml (cluster admin)
|
# First-time setup: kubectl apply -f k8s/rbac-traefik.yaml (cluster admin)
|
||||||
@@ -760,23 +718,19 @@ jobs:
|
|||||||
SUFFIX: ${{ steps.setup.outputs.DEPLOY_SUFFIX }}
|
SUFFIX: ${{ steps.setup.outputs.DEPLOY_SUFFIX }}
|
||||||
ENV: ${{ steps.setup.outputs.ENVIRONMENT }}
|
ENV: ${{ steps.setup.outputs.ENVIRONMENT }}
|
||||||
run: |
|
run: |
|
||||||
kubectl rollout restart deployment/switchboard-be${SUFFIX} -n ${NAMESPACE}
|
kubectl rollout restart deployment/switchboard${SUFFIX} -n ${NAMESPACE}
|
||||||
kubectl rollout restart deployment/switchboard-fe${SUFFIX} -n ${NAMESPACE}
|
kubectl rollout status deployment/switchboard${SUFFIX} -n ${NAMESPACE} --timeout=180s
|
||||||
|
|
||||||
kubectl rollout status deployment/switchboard-be${SUFFIX} -n ${NAMESPACE} --timeout=180s
|
|
||||||
kubectl rollout status deployment/switchboard-fe${SUFFIX} -n ${NAMESPACE} --timeout=180s
|
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
echo "━━━ Pod Status ━━━"
|
echo "━━━ Pod Status ━━━"
|
||||||
kubectl get pods -n ${NAMESPACE} -l app=switchboard,env=${ENV}
|
kubectl get pods -n ${NAMESPACE} -l app=switchboard,env=${ENV}
|
||||||
|
|
||||||
BE_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}')
|
||||||
FE_READY=$(kubectl get deployment switchboard-fe${SUFFIX} -n ${NAMESPACE} -o jsonpath='{.status.readyReplicas}')
|
|
||||||
|
|
||||||
if [[ "${BE_READY:-0}" -gt 0 ]] && [[ "${FE_READY:-0}" -gt 0 ]]; then
|
if [[ "${READY:-0}" -gt 0 ]]; then
|
||||||
echo "✅ Healthy: BE=${BE_READY} FE=${FE_READY} pods ready"
|
echo "✅ Healthy: ${READY} pods ready"
|
||||||
else
|
else
|
||||||
echo "❌ Unhealthy: BE=${BE_READY:-0} FE=${FE_READY:-0}"
|
echo "❌ Unhealthy: ${READY:-0} pods ready"
|
||||||
kubectl logs -n ${NAMESPACE} -l app=switchboard,env=${ENV} --tail=30
|
kubectl logs -n ${NAMESPACE} -l app=switchboard,env=${ENV} --tail=30
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|||||||
10
ROADMAP.md
10
ROADMAP.md
@@ -14,11 +14,11 @@ platform that extensions build on.
|
|||||||
| 2. Delete packages | ✅ | 15 Go packages, 29 handler files removed |
|
| 2. Delete packages | ✅ | 15 Go packages, 29 handler files removed |
|
||||||
| 3. Gut stores/models | ✅ | 40 → 20 store interfaces, kernel-only models |
|
| 3. Gut stores/models | ✅ | 40 → 20 store interfaces, kernel-only models |
|
||||||
| 4. Fresh migrations | ✅ | 9 files × 2 dialects, 27 tables |
|
| 4. Fresh migrations | ✅ | 9 files × 2 dialects, 27 tables |
|
||||||
| 5. Fix compilation | 🔧 | ~95% done, ~5 compile errors remaining |
|
| 5. Fix compilation | ✅ | `go build ./...` clean, 300+ stale route lines cut |
|
||||||
| 6. Fix tests | ⬜ | Prune 13K test lines to kernel-only |
|
| 6. Fix tests | ✅ | 8 test packages pass, ~12K stale test lines pruned |
|
||||||
| 7. Frontend gut | ⬜ | Shell + SDK only, vendor libs baked |
|
| 7. Frontend gut | ✅ | Shell + SDK only, 50+ files of chat/notes/projects code removed |
|
||||||
| 8. New ICD | ⬜ | Kernel-only API spec |
|
| 8. New ICD | 🔧 | Stub in place, full kernel-only spec TBD |
|
||||||
| 9. CI/CD + Dockerfile | ⬜ | Single image, new DB names |
|
| 9. CI/CD + Dockerfile | ✅ | Single unified image, FE/BE split removed, DB names updated |
|
||||||
| 10. Smoke test + tag | ⬜ | Deploy, verify, tag v0.1.0 |
|
| 10. Smoke test + tag | ⬜ | Deploy, verify, tag v0.1.0 |
|
||||||
|
|
||||||
## v0.2.0 — SDK & Triggers
|
## v0.2.0 — SDK & Triggers
|
||||||
|
|||||||
@@ -1,99 +0,0 @@
|
|||||||
# k8s/frontend.yaml
|
|
||||||
# ============================================
|
|
||||||
# Switchboard Core - Frontend Deployment
|
|
||||||
# ============================================
|
|
||||||
# nginx serving the SPA + proxying page routes
|
|
||||||
# to the backend for Go template rendering.
|
|
||||||
#
|
|
||||||
# v0.22.6+: BACKEND_URL enables proxy_pass for
|
|
||||||
# /, /login, /admin, /editor, /notes, /settings.
|
|
||||||
# ============================================
|
|
||||||
apiVersion: apps/v1
|
|
||||||
kind: Deployment
|
|
||||||
metadata:
|
|
||||||
name: switchboard-fe${DEPLOY_SUFFIX}
|
|
||||||
namespace: ${NAMESPACE}
|
|
||||||
labels:
|
|
||||||
app: switchboard
|
|
||||||
component: frontend
|
|
||||||
env: ${ENVIRONMENT}
|
|
||||||
spec:
|
|
||||||
replicas: ${FE_REPLICAS}
|
|
||||||
selector:
|
|
||||||
matchLabels:
|
|
||||||
app: switchboard
|
|
||||||
component: frontend
|
|
||||||
env: ${ENVIRONMENT}
|
|
||||||
template:
|
|
||||||
metadata:
|
|
||||||
labels:
|
|
||||||
app: switchboard
|
|
||||||
component: frontend
|
|
||||||
env: ${ENVIRONMENT}
|
|
||||||
spec:
|
|
||||||
containers:
|
|
||||||
- name: frontend
|
|
||||||
image: ${FE_IMAGE}:${IMAGE_TAG}
|
|
||||||
imagePullPolicy: Always
|
|
||||||
ports:
|
|
||||||
- containerPort: 80
|
|
||||||
name: http
|
|
||||||
env:
|
|
||||||
- name: BASE_PATH
|
|
||||||
value: "${BASE_PATH}"
|
|
||||||
- name: ENVIRONMENT
|
|
||||||
value: "${ENVIRONMENT}"
|
|
||||||
- name: BACKEND_URL
|
|
||||||
value: "http://switchboard-be${DEPLOY_SUFFIX}:8080"
|
|
||||||
volumeMounts:
|
|
||||||
- name: branding
|
|
||||||
mountPath: /branding
|
|
||||||
readOnly: true
|
|
||||||
resources:
|
|
||||||
requests:
|
|
||||||
memory: "${FE_MEMORY_REQUEST}"
|
|
||||||
cpu: "${FE_CPU_REQUEST}"
|
|
||||||
limits:
|
|
||||||
memory: "${FE_MEMORY_LIMIT}"
|
|
||||||
cpu: "${FE_CPU_LIMIT}"
|
|
||||||
readinessProbe:
|
|
||||||
httpGet:
|
|
||||||
path: /healthz
|
|
||||||
port: 80
|
|
||||||
initialDelaySeconds: 3
|
|
||||||
periodSeconds: 10
|
|
||||||
timeoutSeconds: 3
|
|
||||||
failureThreshold: 3
|
|
||||||
livenessProbe:
|
|
||||||
httpGet:
|
|
||||||
path: /healthz
|
|
||||||
port: 80
|
|
||||||
initialDelaySeconds: 5
|
|
||||||
periodSeconds: 30
|
|
||||||
timeoutSeconds: 5
|
|
||||||
failureThreshold: 3
|
|
||||||
volumes:
|
|
||||||
- name: branding
|
|
||||||
configMap:
|
|
||||||
name: switchboard-branding
|
|
||||||
optional: true
|
|
||||||
---
|
|
||||||
apiVersion: v1
|
|
||||||
kind: Service
|
|
||||||
metadata:
|
|
||||||
name: switchboard-fe${DEPLOY_SUFFIX}
|
|
||||||
namespace: ${NAMESPACE}
|
|
||||||
labels:
|
|
||||||
app: switchboard
|
|
||||||
component: frontend
|
|
||||||
env: ${ENVIRONMENT}
|
|
||||||
spec:
|
|
||||||
selector:
|
|
||||||
app: switchboard
|
|
||||||
component: frontend
|
|
||||||
env: ${ENVIRONMENT}
|
|
||||||
ports:
|
|
||||||
- protocol: TCP
|
|
||||||
port: 80
|
|
||||||
targetPort: 80
|
|
||||||
name: http
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
# ==========================================
|
|
||||||
# Switchboard Core - Backend Dockerfile
|
|
||||||
# ==========================================
|
|
||||||
# Standalone Go API server for cluster deployment.
|
|
||||||
# Build context is the repo root (not ./server).
|
|
||||||
# ==========================================
|
|
||||||
|
|
||||||
# Build stage
|
|
||||||
FROM golang:1.23-bookworm AS builder
|
|
||||||
|
|
||||||
ARG APP_VERSION=dev
|
|
||||||
|
|
||||||
WORKDIR /app
|
|
||||||
|
|
||||||
# Copy module files and download deps
|
|
||||||
COPY server/go.mod server/go.sum* ./
|
|
||||||
RUN go mod download
|
|
||||||
|
|
||||||
# Copy source and tidy (resolves any go.sum gaps)
|
|
||||||
COPY server/ .
|
|
||||||
RUN go mod tidy
|
|
||||||
|
|
||||||
# Copy VERSION from repo root — used by ldflags and copied to runtime image.
|
|
||||||
# If APP_VERSION build-arg was supplied by CI, it takes precedence via ldflags.
|
|
||||||
# If not, $(cat VERSION) reads the file directly so the binary always has a real version.
|
|
||||||
COPY VERSION ./
|
|
||||||
RUN CGO_ENABLED=0 go build -ldflags="-s -w -X main.Version=$(cat VERSION)" -o /bin/switchboard .
|
|
||||||
|
|
||||||
# Runtime stage
|
|
||||||
FROM debian:bookworm-slim
|
|
||||||
|
|
||||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
|
||||||
ca-certificates \
|
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
|
||||||
|
|
||||||
COPY --from=builder /bin/switchboard /usr/local/bin/switchboard
|
|
||||||
COPY --from=builder /app/database/migrations /app/database/migrations
|
|
||||||
|
|
||||||
# VERSION file at /VERSION — version.go init() reads it as fallback for local/dev runs
|
|
||||||
COPY --from=builder /app/VERSION /VERSION
|
|
||||||
|
|
||||||
# Builtin extensions (seeded into DB on startup)
|
|
||||||
COPY extensions/builtin/ /app/extensions/builtin/
|
|
||||||
|
|
||||||
WORKDIR /app
|
|
||||||
|
|
||||||
EXPOSE 8080
|
|
||||||
|
|
||||||
ENTRYPOINT ["switchboard"]
|
|
||||||
Reference in New Issue
Block a user