Changeset 0.6.0 (#36)

This commit is contained in:
2026-02-20 22:24:47 +00:00
parent 30d0c11219
commit 925b70f98c
34 changed files with 2575 additions and 637 deletions

View File

@@ -1,6 +1,6 @@
# .gitea/workflows/ci.yaml
# ============================================
# Chat Switchboard - CI/CD Pipeline (v0.5.4)
# Chat Switchboard - CI/CD Pipeline (v0.6.2)
# ============================================
# Cluster deployments use SEPARATE FE + BE images.
# Unified image is for Docker Hub only (docker-compose use).
@@ -9,16 +9,17 @@
# 1. Go test (all PRs and pushes)
# 2. Build + Deploy (depends on test passing)
#
# Deployment mapping:
# PR → FE + BE :dev → dev.DOMAIN (DB wipe + fresh schema)
# Push to main → FE + BE :test → test.DOMAIN (migrate only)
# Tag v* → FE + BE :latest → www.DOMAIN (migrate only)
# → Unified :latest → Docker Hub (not deployed)
# Deployment mapping (single domain, path-based):
# PR → FE + BE :dev → switchboard.DOMAIN/dev/ (DB wipe + fresh schema)
# Push to main → FE + BE :test → switchboard.DOMAIN/test/ (migrate only)
# Tag v* → FE + BE :latest → switchboard.DOMAIN/ (migrate only)
# → Unified :latest → Docker Hub (not deployed)
#
# Database lifecycle:
# CI: bootstrap (admin creds) → create DB + role + extensions
# CI: dev wipe (app creds) → drop tables for fresh install test
# BE: auto-migrate on startup → schema_migrations tracking
# BE: bootstrap admin from SWITCHBOARD_ADMIN_* env vars (upsert on every restart)
#
# Shared PG safety:
# - Bootstrap uses IF NOT EXISTS (idempotent)
@@ -32,6 +33,7 @@
# Required Gitea Secrets:
# POSTGRES_USER, POSTGRES_PASSWORD
# POSTGRES_ADMIN_USER, POSTGRES_ADMIN_PASSWORD
# SWITCHBOARD_ADMIN_USERNAME, SWITCHBOARD_ADMIN_PASSWORD, SWITCHBOARD_ADMIN_EMAIL
# DOCKERHUB_USERNAME, DOCKERHUB_TOKEN (optional)
#
# Global Variables (Gitea org-level):
@@ -111,10 +113,15 @@ jobs:
- name: Determine environment
id: env
run: |
# All environments share one host: switchboard.DOMAIN
# Environments are separated by path prefix (BASE_PATH)
DEPLOY_HOST="switchboard.${DOMAIN}"
echo "DEPLOY_HOST=${DEPLOY_HOST}" >> "$GITHUB_OUTPUT"
if [[ "${{ gitea.event_name }}" == "pull_request" ]]; then
echo "ENVIRONMENT=dev" >> "$GITHUB_OUTPUT"
echo "IMAGE_TAG=dev" >> "$GITHUB_OUTPUT"
echo "DEPLOY_HOST=dev.${DOMAIN}" >> "$GITHUB_OUTPUT"
echo "BASE_PATH=/dev" >> "$GITHUB_OUTPUT"
echo "DEPLOY_SUFFIX=-dev" >> "$GITHUB_OUTPUT"
echo "DB_NAME=chat_switchboard_dev" >> "$GITHUB_OUTPUT"
echo "DB_WIPE=true" >> "$GITHUB_OUTPUT"
@@ -134,7 +141,7 @@ jobs:
echo "ENVIRONMENT=production" >> "$GITHUB_OUTPUT"
echo "IMAGE_TAG=latest" >> "$GITHUB_OUTPUT"
echo "EXTRA_TAG=${VERSION}" >> "$GITHUB_OUTPUT"
echo "DEPLOY_HOST=www.${DOMAIN}" >> "$GITHUB_OUTPUT"
echo "BASE_PATH=" >> "$GITHUB_OUTPUT"
echo "DEPLOY_SUFFIX=" >> "$GITHUB_OUTPUT"
echo "DB_NAME=chat_switchboard" >> "$GITHUB_OUTPUT"
echo "DB_WIPE=false" >> "$GITHUB_OUTPUT"
@@ -153,7 +160,7 @@ jobs:
else
echo "ENVIRONMENT=test" >> "$GITHUB_OUTPUT"
echo "IMAGE_TAG=test" >> "$GITHUB_OUTPUT"
echo "DEPLOY_HOST=test.${DOMAIN}" >> "$GITHUB_OUTPUT"
echo "BASE_PATH=/test" >> "$GITHUB_OUTPUT"
echo "DEPLOY_SUFFIX=-test" >> "$GITHUB_OUTPUT"
echo "DB_NAME=chat_switchboard_test" >> "$GITHUB_OUTPUT"
echo "DB_WIPE=false" >> "$GITHUB_OUTPUT"
@@ -350,11 +357,24 @@ jobs:
kubectl create namespace ${NAMESPACE} 2>/dev/null || true
- name: Sync secrets
env:
PG_USER: ${{ secrets.POSTGRES_USER }}
PG_PASS: ${{ secrets.POSTGRES_PASSWORD }}
SW_ADMIN_USER: ${{ secrets.SWITCHBOARD_ADMIN_USERNAME }}
SW_ADMIN_PASS: ${{ secrets.SWITCHBOARD_ADMIN_PASSWORD }}
SW_ADMIN_EMAIL: ${{ secrets.SWITCHBOARD_ADMIN_EMAIL }}
run: |
kubectl create secret generic switchboard-db-credentials \
--namespace=${NAMESPACE} \
--from-literal=POSTGRES_USER=${{ secrets.POSTGRES_USER }} \
--from-literal=POSTGRES_PASSWORD=${{ secrets.POSTGRES_PASSWORD }} \
--from-literal=POSTGRES_USER="${PG_USER}" \
--from-literal=POSTGRES_PASSWORD="${PG_PASS}" \
--dry-run=client -o yaml | kubectl apply -f -
kubectl create secret generic switchboard-admin \
--namespace=${NAMESPACE} \
--from-literal=username="${SW_ADMIN_USER}" \
--from-literal=password="${SW_ADMIN_PASS}" \
--from-literal=email="${SW_ADMIN_EMAIL}" \
--dry-run=client -o yaml | kubectl apply -f -
- name: Render and apply manifests
@@ -363,6 +383,7 @@ jobs:
IMAGE_TAG: ${{ steps.env.outputs.IMAGE_TAG }}
DEPLOY_SUFFIX: ${{ steps.env.outputs.DEPLOY_SUFFIX }}
DEPLOY_HOST: ${{ steps.env.outputs.DEPLOY_HOST }}
BASE_PATH: ${{ steps.env.outputs.BASE_PATH }}
DB_NAME: ${{ steps.env.outputs.DB_NAME }}
FE_REPLICAS: ${{ steps.env.outputs.FE_REPLICAS }}
BE_REPLICAS: ${{ steps.env.outputs.BE_REPLICAS }}
@@ -415,7 +436,8 @@ jobs:
run: |
sleep 5
HOST="${{ steps.env.outputs.DEPLOY_HOST }}"
HEALTH=$(curl -sf "https://${HOST}/api/v1/health" 2>/dev/null || echo "unreachable")
BP="${{ steps.env.outputs.BASE_PATH }}"
HEALTH=$(curl -sf "https://${HOST}${BP}/api/v1/health" 2>/dev/null || echo "unreachable")
echo "Health: ${HEALTH}"
# Extract fields (|| true prevents set -e from killing on no-match)
@@ -432,11 +454,12 @@ jobs:
- name: Summary
run: |
HOST="${{ steps.env.outputs.DEPLOY_HOST }}"
BP="${{ steps.env.outputs.BASE_PATH }}"
echo "## ✅ Deployed to ${{ steps.env.outputs.env_label }}" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "| | |" >> $GITHUB_STEP_SUMMARY
echo "|---|---|" >> $GITHUB_STEP_SUMMARY
echo "| **URL** | https://${HOST} |" >> $GITHUB_STEP_SUMMARY
echo "| **URL** | https://${HOST}${BP}/ |" >> $GITHUB_STEP_SUMMARY
echo "| **Backend** | \`${BE_IMAGE}:${{ steps.env.outputs.IMAGE_TAG }}\` |" >> $GITHUB_STEP_SUMMARY
echo "| **Frontend** | \`${FE_IMAGE}:${{ steps.env.outputs.IMAGE_TAG }}\` |" >> $GITHUB_STEP_SUMMARY
echo "| **Database** | \`${{ steps.env.outputs.DB_NAME }}\` |" >> $GITHUB_STEP_SUMMARY