step 5 (continued): prune stale root files, drop frontend split
Some checks failed
CI/CD / detect-changes (push) Successful in 22s
CI/CD / test-go-pg (push) Failing after 21s
CI/CD / test-frontend (push) Successful in 25s
CI/CD / test-sqlite (push) Failing after 37s
CI/CD / build-and-deploy (push) Has been skipped

Delete Dockerfile.frontend and docker-entrypoint-fe.sh (single-image
decision per ROADMAP). Remove gutted /chat, /notes, /projects routes
from nginx.conf. Fix Chat Switchboard branding in entrypoint and
.env.example. Update DB names to switchboard_core, remove dead
Extraction config.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-26 09:27:22 +00:00
parent 7b6e54d5b7
commit a9c652ff59
6 changed files with 9 additions and 276 deletions

View File

@@ -1,65 +0,0 @@
# ==========================================
# Switchboard Core - Frontend Dockerfile
# ==========================================
# Static SPA served by nginx. In k8s, the
# Ingress routes /api/ and /ws to the backend
# service directly.
#
# Supports path-based deployment via BASE_PATH
# env var (e.g. /dev, /test, or empty for root).
# The entrypoint generates the nginx config and
# injects BASE_PATH into index.html at startup.
#
# v0.22.6+: Set BACKEND_URL to proxy page routes
# (/, /login, /admin, /editor, /notes, /settings)
# to the Go backend for server-rendered templates.
# When unset, page routes fall through to SPA.
#
# Build context: repo root
# ==========================================
# Stage 1: Download vendor libs (vendor/ is gitignored)
FROM node:20-alpine AS vendor
WORKDIR /tmp
RUN npm pack marked@16.3.0 dompurify@3.2.4 mermaid@11.4.1 katex@0.16.11 2>/dev/null && \
mkdir -p /vendor/mermaid /vendor/katex/fonts && \
tar xzf marked-*.tgz -C /tmp && cp /tmp/package/lib/marked.umd.js /vendor/marked.min.js && \
rm -rf /tmp/package && \
tar xzf dompurify-*.tgz -C /tmp && cp /tmp/package/dist/purify.min.js /vendor/purify.min.js && \
rm -rf /tmp/package && \
tar xzf mermaid-*.tgz -C /tmp && cp /tmp/package/dist/mermaid.min.js /vendor/mermaid/mermaid.min.js && \
rm -rf /tmp/package && \
tar xzf katex-*.tgz -C /tmp && \
cp /tmp/package/dist/katex.min.js /vendor/katex/katex.min.js && \
cp /tmp/package/dist/katex.min.css /vendor/katex/katex.min.css && \
cp -r /tmp/package/dist/fonts/* /vendor/katex/fonts/ && \
rm -rf /tmp/package /tmp/*.tgz
# Stage 2: CM6 editor bundle (esbuild → single IIFE)
FROM node:20-alpine AS cm6-build
WORKDIR /build
COPY src/editor/ /build/src/editor/
COPY scripts/build-editor.sh /build/scripts/build-editor.sh
RUN cd /build/src/editor && npm ci --loglevel=warn
RUN sh /build/scripts/build-editor.sh /build/dist
# Stage 3: nginx + entrypoint
FROM nginx:1-alpine
# Remove default config — entrypoint generates it
RUN rm -f /etc/nginx/conf.d/default.conf
COPY src/ /usr/share/nginx/html/
COPY --from=vendor /vendor/ /usr/share/nginx/html/vendor/
COPY --from=cm6-build /build/dist/ /usr/share/nginx/html/vendor/codemirror/
COPY VERSION /VERSION
COPY docker-entrypoint-fe.sh /docker-entrypoint-fe.sh
RUN chmod +x /docker-entrypoint-fe.sh
EXPOSE 80
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD wget --no-verbose --tries=1 --spider http://localhost/healthz 2>/dev/null || \
wget --no-verbose --tries=1 --spider http://localhost/ || exit 1
ENTRYPOINT ["/docker-entrypoint-fe.sh"]

View File

@@ -10,7 +10,7 @@
# Data persists in ./data/ between restarts. # Data persists in ./data/ between restarts.
# To reset: rm -rf ./data/ # To reset: rm -rf ./data/
# #
# For Postgres / multi-replica / k8s deployment see k8s/ and server/Dockerfile + Dockerfile.frontend. # For Postgres / multi-replica / k8s deployment see k8s/ and Dockerfile.
services: services:
switchboard: switchboard:

View File

@@ -1,190 +0,0 @@
#!/bin/sh
# ============================================
# Chat Switchboard - Frontend Entrypoint
# ============================================
# nginx serves static assets and proxies page
# routes to the Go backend for template rendering.
# API/WS routes are handled by Ingress directly.
#
# Environment (required):
# BACKEND_URL - Backend service URL
# (e.g. "http://switchboard-be:8080")
#
# Environment (optional):
# BASE_PATH - URL prefix (e.g. "/dev", "" for root)
# ENVIRONMENT - Environment name for logging
# ============================================
set -e
BASE_PATH="${BASE_PATH:-}"
BACKEND_URL="${BACKEND_URL:?BACKEND_URL is required (e.g. http://switchboard-be:8080)}"
ENVIRONMENT="${ENVIRONMENT:-production}"
# Read version from VERSION file (baked in at build time)
APP_VERSION="dev"
if [ -f /VERSION ]; then
APP_VERSION=$(cat /VERSION | tr -d '[:space:]')
fi
# Compute build hash from JS file contents (unique per deploy)
BUILD_HASH=$(find /usr/share/nginx/html/js -name '*.js' -exec md5sum {} + 2>/dev/null | sort | md5sum | cut -c1-8)
if [ -z "${BUILD_HASH}" ]; then
BUILD_HASH=$(date +%s | md5sum | cut -c1-8)
fi
# ── Inject into index.html (redirect page) ──
sed -i \
-e "s|%%BASE_PATH%%|${BASE_PATH}|g" \
-e "s|%%APP_VERSION%%|${APP_VERSION}|g" \
/usr/share/nginx/html/index.html
# Inject version and build hash into service worker
sed -i \
-e "s|%%APP_VERSION%%|${APP_VERSION}|g" \
-e "s|%%BUILD_HASH%%|${BUILD_HASH}|g" \
/usr/share/nginx/html/sw.js
echo "✅ Frontend: BASE_PATH=${BASE_PATH:-/} VERSION=${APP_VERSION} BUILD=${BUILD_HASH} BACKEND=${BACKEND_URL}"
# ── Page route proxy blocks ─────────────────
page_proxy_block() {
local path="$1"
cat <<PROXY
location ${path} {
proxy_pass ${BACKEND_URL};
proxy_http_version 1.1;
proxy_set_header Host \$host;
proxy_set_header X-Real-IP \$remote_addr;
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto \$scheme;
}
PROXY
}
PAGE_ROUTES=$(cat <<ROUTES
# ── Page routes → backend ────────────────
$(page_proxy_block "= ${BASE_PATH}/")
$(page_proxy_block "= ${BASE_PATH}/login")
location ~ ^${BASE_PATH}/chat/[^/]+\$ {
proxy_pass ${BACKEND_URL};
proxy_http_version 1.1;
proxy_set_header Host \$host;
proxy_set_header X-Real-IP \$remote_addr;
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto \$scheme;
}
$(page_proxy_block "${BASE_PATH}/admin")
$(page_proxy_block "${BASE_PATH}/editor")
$(page_proxy_block "${BASE_PATH}/notes")
$(page_proxy_block "${BASE_PATH}/projects")
$(page_proxy_block "${BASE_PATH}/settings")
$(page_proxy_block "${BASE_PATH}/w")
# v0.27.0: Extension surface page routes
$(page_proxy_block "${BASE_PATH}/s")
# v0.27.0: Extension surface static assets (proxied to backend; on-disk at /data/packages/)
$(page_proxy_block "${BASE_PATH}/surfaces")
ROUTES
)
# ── Generate nginx config ───────────────────
if [ -z "${BASE_PATH}" ]; then
cat > /etc/nginx/conf.d/default.conf <<NGINX
server {
listen 80;
server_name _;
root /usr/share/nginx/html;
index index.html;
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_proxied expired no-cache no-store private auth;
gzip_types text/plain text/css text/xml text/javascript application/x-javascript application/xml application/javascript;
location ~* \.(jpg|jpeg|png|gif|ico|css|js|woff|woff2)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
location = /sw.js {
expires off;
add_header Cache-Control "no-cache, no-store, must-revalidate";
}
location /branding/ {
alias /branding/;
expires 1h;
add_header Cache-Control "public";
try_files \$uri =404;
}
${PAGE_ROUTES}
location / {
try_files \$uri \$uri/ /index.html;
}
location = /healthz {
return 200 'ok';
add_header Content-Type text/plain;
}
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
}
NGINX
else
cat > /etc/nginx/conf.d/default.conf <<NGINX
server {
listen 80;
server_name _;
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_proxied expired no-cache no-store private auth;
gzip_types text/plain text/css text/xml text/javascript application/x-javascript application/xml application/javascript;
${PAGE_ROUTES}
location ${BASE_PATH}/ {
alias /usr/share/nginx/html/;
try_files \$uri \$uri/ ${BASE_PATH}/index.html;
location ~* \.(jpg|jpeg|png|gif|ico|css|js|woff|woff2)\$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
location = ${BASE_PATH}/sw.js {
alias /usr/share/nginx/html/sw.js;
expires off;
add_header Cache-Control "no-cache, no-store, must-revalidate";
}
}
location ${BASE_PATH}/branding/ {
alias /branding/;
expires 1h;
add_header Cache-Control "public";
try_files \$uri =404;
}
location = ${BASE_PATH} {
return 301 ${BASE_PATH}/;
}
location = /healthz {
return 200 'ok';
add_header Content-Type text/plain;
}
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
}
NGINX
fi
exec nginx -g 'daemon off;'

View File

@@ -1,6 +1,6 @@
#!/bin/bash #!/bin/bash
# ============================================ # ============================================
# Chat Switchboard - Backend Launcher # Switchboard Core - Backend Launcher
# ============================================ # ============================================
# Runs as an nginx entrypoint.d hook. # Runs as an nginx entrypoint.d hook.
# Starts the Go backend in the background # Starts the Go backend in the background
@@ -9,7 +9,7 @@
set -e set -e
echo "🔀 Starting Chat Switchboard backend..." echo "🔀 Starting Switchboard Core backend..."
# Launch Go backend in background (from /app so migrations are found) # Launch Go backend in background (from /app so migrations are found)
cd /app cd /app

View File

@@ -68,19 +68,9 @@ server {
proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Real-IP $remote_addr;
} }
location ~ ^/chat/[^/]+$ {
proxy_pass $backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
location /admin { proxy_pass $backend; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } location /admin { proxy_pass $backend; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; }
location /team-admin { proxy_pass $backend; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } location /team-admin { proxy_pass $backend; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; }
location /notes { proxy_pass $backend; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; }
location /settings { proxy_pass $backend; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } location /settings { proxy_pass $backend; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; }
location /projects { proxy_pass $backend; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; }
location /w/ { proxy_pass $backend; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } location /w/ { proxy_pass $backend; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; }
# v0.27.0: Extension surface page routes → backend (Go templates) # v0.27.0: Extension surface page routes → backend (Go templates)

View File

@@ -1,4 +1,4 @@
# Chat Switchboard v0.12 - Server Environment Variables # Switchboard Core - Server Environment Variables
# Copy this file to .env and fill in the values # Copy this file to .env and fill in the values
# ── Server ─────────────────────────────────── # ── Server ───────────────────────────────────
@@ -9,15 +9,17 @@ BASE_PATH= # e.g. /chat for path-based routing
# ── Database (PostgreSQL) ──────────────────── # ── Database (PostgreSQL) ────────────────────
DB_HOST=localhost DB_HOST=localhost
DB_PORT=5432 DB_PORT=5432
DB_USER=chat_switchboard DB_USER=switchboard_core
DB_PASSWORD=your-secure-password-here DB_PASSWORD=your-secure-password-here
DB_NAME=chat_switchboard DB_NAME=switchboard_core
DB_SSL_MODE=disable DB_SSL_MODE=disable
DB_MAX_CONNS=25 DB_MAX_CONNS=25
# ── Auth ───────────────────────────────────── # ── Auth ─────────────────────────────────────
JWT_SECRET=your-super-secret-jwt-key-change-in-production JWT_SECRET=your-super-secret-jwt-key-change-in-production
JWT_EXPIRATION=24h # JWT durations (hardcoded in handlers/auth.go — not configurable via env):
# Access token: 15 minutes
# Refresh token: 7 days
JWT_ISSUER=switchboard-core JWT_ISSUER=switchboard-core
# ── Bootstrap Admin ────────────────────────── # ── Bootstrap Admin ──────────────────────────
@@ -61,7 +63,3 @@ STORAGE_PATH=/data/storage
# S3_REGION=us-east-1 # S3_REGION=us-east-1
# S3_PREFIX= # optional key prefix for shared buckets # S3_PREFIX= # optional key prefix for shared buckets
# S3_FORCE_PATH_STYLE=true # required for MinIO, Ceph RGW # S3_FORCE_PATH_STYLE=true # required for MinIO, Ceph RGW
# ── Extraction ───────────────────────────────
# EXTRACTION_MODE=inline # "inline" or "sidecar"
# EXTRACTION_CONCURRENCY=3