Compare commits

..

No commits in common. "fdc5015765040446755b6b022a54db2539ad9411" and "7ec8741ba800974418e4bbc808f95b9f55049d50" have entirely different histories.

9 changed files with 1 additions and 1150 deletions

View File

@ -1,260 +0,0 @@
# ByteLyst Production Deployment Guide
## Overview
This directory contains production deployment scripts for ByteLyst services.
## Production Repos
- `learning_ai_invt_trdg` - Trading Platform (https://api.bytelyst.com/invttrdg, https://invttrdg.bytelyst.com)
- `learning_ai_common_plat` - Platform Services (auth, flags, telemetry, etc.)
- `learning_ai_clock` - ChronoMind (AI-powered time management)
- `learning_ai_notes` - NoteLett (Agentic note-taking)
## Deployment Scripts
### 1. Single Repo Deployment (`deploy-invttrdg.sh`)
Deploy only the investment trading platform with comprehensive testing.
```bash
# Standard deployment (with dirty checks + smoke tests)
./deploy-invttrdg.sh
# Force deployment (skip dirty checks + smoke tests)
./deploy-invttrdg.sh --force
# Skip health checks and smoke tests
./deploy-invttrdg.sh --skip-health-check
```
**What it does:**
1. Dirty check (uncommitted changes, unpushed commits)
2. Pull and rebase origin/main
3. **Pre-deployment smoke tests:**
- Backend contract checks (API, audit repository, WebSocket, session rules)
- Web typecheck + production build
- Web DOM smoke tests (auth, kill-switch, components)
- Mobile typecheck compilation
4. Build and deploy Docker containers (backend + web)
5. **Post-deployment validation:**
- Health checks on localhost endpoints
- Production endpoint verification (api.bytelyst.com, invttrdg.bytelyst.com)
- API smoke tests (health endpoint, content validation)
- Web frontend validation (HTML content check)
### 2. Multi-Repo Deployment (`deploy-all.sh`)
Deploy all production repos or specific ones.
```bash
# Deploy all production repos
./deploy-all.sh
# Deploy specific repos
./deploy-all.sh learning_ai_invt_trdg learning_ai_clock
# Force deployment (skip dirty checks)
./deploy-all.sh --force
# Skip health checks
./deploy-all.sh --skip-health-check
# Deploy specific repos with force
./deploy-all.sh --force learning_ai_invt_trdg
```
**What it does:**
1. Runs dirty checks for each repo
2. Pulls and rebases origin/main for each repo
3. Builds and deploys Docker containers
4. Runs health checks on all services
## Service Endpoints
### Investment Trading (learning_ai_invt_trdg)
**Docker Services Deployed:**
- **Backend:** `invttrdg-backend` (port 4018 → mapped to 4025)
- Trading engine + REST API + Socket.IO
- Health endpoint: `/health/live`
- API endpoints for trading operations
- **Web:** `invttrdg-web` (port 3085)
- Vite SPA served via nginx
- React trading interface
**Exposed Endpoints:**
- **Local Backend API:** http://localhost:4025
- **Local Web App:** http://localhost:3085
- **Production API:** https://api.bytelyst.com/invttrdg (via Caddy reverse proxy)
- **Production Web:** https://invttrdg.bytelyst.com (via Caddy reverse proxy)
### Platform Services (learning_ai_common_plat)
- **Platform Service:** http://localhost:4003
- **Extraction Service:** http://localhost:4005
- **MCP Server:** http://localhost:4007
- **Admin Web:** http://localhost:3001
- **Tracker Web:** http://localhost:3003
### ChronoMind (learning_ai_clock)
- **Backend:** http://localhost:4011
- **Web:** http://localhost:3030
### NoteLett (learning_ai_notes)
- **Backend:** http://localhost:4016
- **Web:** http://localhost:3000
## Docker Management
### Check running containers
```bash
docker ps
```
### View logs
```bash
# Specific repo
cd learning_ai_invttrdg
docker compose logs -f
# All containers
docker compose -f learning_ai_common_plat/docker-compose.ecosystem.yml logs -f
```
### Restart services
```bash
# Specific repo
cd learning_ai_invttrdg
docker compose restart
# All services
docker compose -f learning_ai_common_plat/docker-compose.ecosystem.yml restart
```
### Stop services
```bash
# Specific repo
cd learning_ai_invttrdg
docker compose down
# All services
docker compose -f learning_ai_common_plat/docker-compose.ecosystem.yml down
```
## Troubleshooting
### Dirty Check Failures
If deployment fails due to uncommitted changes:
```bash
# Option 1: Commit changes
cd learning_ai_invttrdg
git add .
git commit -m "Your commit message"
# Option 2: Stash changes
git stash
# Option 3: Force deployment
./deploy-invttrdg.sh --force
```
### Rebase Conflicts
If rebase fails due to conflicts:
```bash
cd learning_ai_invttrdg
# Resolve conflicts
git add .
git rebase --continue
```
### Health Check Failures
If health checks fail but services are starting:
```bash
# Skip health checks and smoke tests
./deploy-invttrdg.sh --skip-health-check
# Check manually
curl http://localhost:4025/health/live
curl http://localhost:3085
```
### Smoke Test Failures
If pre-deployment smoke tests fail:
```bash
# Run smoke tests manually to debug
cd learning_ai_invt_trdg
./scripts/smoke-release.sh
# Run individual backend checks
cd backend
npm run check:api-contract
npm run check:websocket-contract
npm run check:session-rule-normalization
# Run web tests individually
cd ../web
pnpm vitest run src/components/Login.dom.test.tsx
```
### Docker Build Failures
If Docker build fails:
```bash
# Clean build
cd learning_ai_invttrdg
docker compose build --no-cache
# Check disk space
df -h
```
## DNS Configuration
DNS is managed via GoDaddy. To update DNS records:
```bash
cd learning_ai_common_plat
./scripts/godaddy-sync-bytelyst-dns.sh --ip <YOUR_VM_IP> --validate
```
## Monitoring
### Health Check Script
```bash
./check-health.sh
```
### View Logs
- **Grafana:** http://localhost:3000 (admin/bytelyst)
- **Loki:** http://localhost:3100
- **Traefik Dashboard:** http://localhost:8080
## Production Checklist
Before deploying to production:
- [ ] All tests pass locally
- [ ] No uncommitted changes
- [ ] No unpushed commits
- [ ] Environment variables are set correctly
- [ ] DNS records point to correct IP
- [ ] Database migrations are applied
- [ ] Backup current deployment
- [ ] Monitor logs after deployment
## Rollback
If deployment causes issues:
```bash
cd learning_ai_invttrdg
# Revert to previous commit
git log --oneline -5
git revert <commit-hash>
# Redeploy
docker compose up -d --build
```

View File

@ -12,8 +12,6 @@ Run the installer:
The installer detects macOS/Linux and Bash/Zsh, then adds a managed source block to the right startup file. It is safe to run more than once and creates a timestamped backup before changing the startup file. The installer detects macOS/Linux and Bash/Zsh, then adds a managed source block to the right startup file. It is safe to run more than once and creates a timestamped backup before changing the startup file.
After running the installer, open a new shell or run `source ~/.zshrc` for Zsh or `source ~/.bashrc` / `source ~/.bash_profile` for Bash. A shell script cannot add aliases to the already-running parent shell by itself.
Preview the change without writing files: Preview the change without writing files:
```bash ```bash

View File

@ -178,9 +178,6 @@ remove_existing_block "$target_rc" "$tmp_file"
if cmp -s "$target_rc" "$new_file"; then if cmp -s "$target_rc" "$new_file"; then
echo echo
echo "ByteLyst aliases are already installed." echo "ByteLyst aliases are already installed."
echo "They will be available in new shell sessions."
echo "To use them in this shell now, run:"
echo " source \"$target_rc\""
exit 0 exit 0
fi fi
@ -191,6 +188,5 @@ cat "$new_file" > "$target_rc"
echo echo
echo "Installed ByteLyst aliases." echo "Installed ByteLyst aliases."
echo "Backup created: $backup_file" echo "Backup created: $backup_file"
echo "They will be available in new shell sessions." echo "Open a new shell or run:"
echo "To use them in this shell now, run:"
echo " source \"$target_rc\"" echo " source \"$target_rc\""

View File

@ -1,194 +0,0 @@
#!/usr/bin/env bash
set -euo pipefail
# ═══════════════════════════════════════════════════════════════════════
# ByteLyst Production Deployment - All Repos
# ═══════════════════════════════════════════════════════════════════════
# Usage: ./deploy-all.sh [--force] [--skip-health-check] [repo1 repo2 ...]
#
# Deploys all production repos or specific repos:
# - learning_ai_invt_trdg (Trading)
# - learning_ai_common_plat (Platform Services)
# - learning_ai_clock (ChronoMind)
# - learning_ai_notes (NoteLett)
#
# Options:
# --force Skip dirty checks and force deployment
# --skip-health-check Skip endpoint health verification
# ═══════════════════════════════════════════════════════════════════════
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; CYAN='\033[0;36m'; NC='\033[0m'
log() { echo -e "${CYAN}[$(date +%H:%M:%S)]${NC} $*"; }
ok() { echo -e "${GREEN}[$(date +%H:%M:%S)] ✓${NC} $*"; }
warn() { echo -e "${YELLOW}[$(date +%H:%M:%S)] ⚠${NC} $*"; }
fail() { echo -e "${RED}[$(date +%H:%M:%S)] ✗${NC} $*"; exit 1; }
# ── Configuration ────────────────────────────────────────────────────
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
REPOS_BASE_DIR="${SCRIPT_DIR}/.."
cd "$SCRIPT_DIR"
PRODUCTION_REPOS=(
"learning_ai_invt_trdg"
"learning_ai_common_plat"
"learning_ai_clock"
"learning_ai_notes"
)
FORCE=false
SKIP_HEALTH_CHECK=false
SPECIFIC_REPOS=()
while [[ $# -gt 0 ]]; do
case "$1" in
--force) FORCE=true; shift ;;
--skip-health-check) SKIP_HEALTH_CHECK=true; shift ;;
-*) fail "Unknown option: $1" ;;
*) SPECIFIC_REPOS+=("$1"); shift ;;
esac
done
# If specific repos provided, validate them
if [ ${#SPECIFIC_REPOS[@]} -gt 0 ]; then
for repo in "${SPECIFIC_REPOS[@]}"; do
valid=false
for valid_repo in "${PRODUCTION_REPOS[@]}"; do
if [ "$repo" = "$valid_repo" ]; then
valid=true
break
fi
done
if [ "$valid" = false ]; then
fail "Unknown repo: $repo. Valid repos: ${PRODUCTION_REPOS[*]}"
fi
done
REPOS_TO_DEPLOY=("${SPECIFIC_REPOS[@]}")
else
REPOS_TO_DEPLOY=("${PRODUCTION_REPOS[@]}")
fi
# ── Deploy Function ───────────────────────────────────────────────────
deploy_repo() {
local repo="$1"
local repo_dir="${REPOS_BASE_DIR}/${repo}"
log "══════════════════════════════════════════════════════════════════════"
log "Deploying: $repo"
log "══════════════════════════════════════════════════════════════════════"
if [ ! -d "$repo_dir" ]; then
fail "Repo directory not found: $repo_dir"
fi
cd "$repo_dir"
# ── Dirty Check ───────────────────────────────────────────────────
if [ "$FORCE" = false ]; then
log "Running dirty checks for $repo..."
if ! git diff-index --quiet HEAD --; then
fail "Uncommitted changes in $repo. Commit or stash first, or use --force"
fi
if [ -n "$(git ls-files --others --exclude-standard)" ]; then
fail "Untracked files in $repo. Commit or remove them, or use --force"
fi
LOCAL_COMMIT=$(git rev-parse @)
REMOTE_COMMIT=$(git rev-parse '@{u}' 2>/dev/null || echo "")
if [ -n "$REMOTE_COMMIT" ] && [ "$LOCAL_COMMIT" != "$REMOTE_COMMIT" ]; then
fail "Unpushed commits in $repo. Push first or use --force"
fi
ok "Dirty checks passed for $repo"
else
warn "Skipping dirty checks for $repo (--force enabled)"
fi
# ── Pull and Rebase ───────────────────────────────────────────────
log "Pulling latest changes for $repo..."
git fetch origin
LOCAL_MAIN=$(git rev-parse main)
REMOTE_MAIN=$(git rev-parse origin/main)
if [ "$LOCAL_MAIN" != "$REMOTE_MAIN" ]; then
log "Local main is behind origin/main, rebasing $repo..."
git rebase origin/main || {
fail "Rebase failed for $repo. Resolve conflicts and run: git rebase --continue"
}
ok "Rebase completed for $repo"
else
ok "$repo is already up to date"
fi
# ── Build and Deploy ───────────────────────────────────────────────
if [ -f "docker-compose.yml" ]; then
log "Building and deploying $repo..."
docker compose build || fail "Docker build failed for $repo"
docker compose up -d || fail "Docker compose up failed for $repo"
ok "Deployment completed for $repo"
else
warn "No docker-compose.yml found in $repo, skipping Docker deployment"
fi
cd "$REPOS_BASE_DIR"
}
# ── Deploy All Repos ───────────────────────────────────────────────────
FAILED_REPOS=()
SUCCESSFUL_REPOS=()
for repo in "${REPOS_TO_DEPLOY[@]}"; do
if deploy_repo "$repo"; then
SUCCESSFUL_REPOS+=("$repo")
else
FAILED_REPOS+=("$repo")
fi
done
# ── Summary ─────────────────────────────────────────────────────────────
log "══════════════════════════════════════════════════════════════════════"
log "Deployment Summary"
log "══════════════════════════════════════════════════════════════════════"
if [ ${#SUCCESSFUL_REPOS[@]} -gt 0 ]; then
ok "Successfully deployed: ${SUCCESSFUL_REPOS[*]}"
fi
if [ ${#FAILED_REPOS[@]} -gt 0 ]; then
fail "Failed to deploy: ${FAILED_REPOS[*]}"
fi
# ── Health Checks (if not skipped) ───────────────────────────────────────
if [ "$SKIP_HEALTH_CHECK" = false ]; then
log "Running health checks..."
# Define health endpoints for each service
declare -A HEALTH_ENDPOINTS=(
["learning_ai_invt_trdg"]="http://localhost:4025/health/live"
["learning_ai_common_plat"]="http://localhost:4003/health"
["learning_ai_clock"]="http://localhost:4011/health"
["learning_ai_notes"]="http://localhost:4016/health"
)
for repo in "${SUCCESSFUL_REPOS[@]}"; do
endpoint="${HEALTH_ENDPOINTS[$repo]:-}"
if [ -n "$endpoint" ]; then
log "Checking $repo at $endpoint"
if curl -sf "$endpoint" > /dev/null 2>&1; then
ok "$repo is healthy"
else
warn "$repo health check failed (may still be starting)"
fi
fi
done
else
warn "Skipping health checks (--skip-health-check enabled)"
fi
log "══════════════════════════════════════════════════════════════════════"
ok "All deployments completed successfully!"
log "══════════════════════════════════════════════════════════════════════"

View File

@ -1,233 +0,0 @@
#!/usr/bin/env bash
set -euo pipefail
# ═══════════════════════════════════════════════════════════════════════
# ByteLyst ChronoMind - Production Deployment Script
# ═══════════════════════════════════════════════════════════════════════
# Usage: ./deploy-clock.sh [--force] [--skip-health-check]
#
# What it does:
# 1. Dirty check: uncommitted changes, unpushed commits
# 2. Pull and rebase origin/main
# 3. Build and deploy Docker containers
# 4. Verify endpoints: https://api.bytelyst.com/chronomind, http://localhost:3030
#
# Options:
# --force Skip dirty checks and force deployment
# --skip-health-check Skip endpoint health verification
# ═══════════════════════════════════════════════════════════════════════
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; CYAN='\033[0;36m'; NC='\033[0m'
log() { echo -e "${CYAN}[$(date +%H:%M:%S)]${NC} $*"; }
ok() { echo -e "${GREEN}[$(date +%H:%M:%S)] ✓${NC} $*"; }
warn() { echo -e "${YELLOW}[$(date +%H:%M:%S)] ⚠${NC} $*"; }
fail() { echo -e "${RED}[$(date +%H:%M:%S)] ✗${NC} $*"; exit 1; }
# ── Configuration ────────────────────────────────────────────────────
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
REPO_DIR="${SCRIPT_DIR}/../learning_ai_clock"
cd "$SCRIPT_DIR"
FORCE=false
SKIP_HEALTH_CHECK=false
while [[ $# -gt 0 ]]; do
case "$1" in
--force) FORCE=true; shift ;;
--skip-health-check) SKIP_HEALTH_CHECK=true; shift ;;
*) fail "Unknown option: $1" ;;
esac
done
# ── Prerequisites ────────────────────────────────────────────────────
if [ ! -d "$REPO_DIR" ]; then
fail "Repo directory not found: $REPO_DIR"
fi
cd "$REPO_DIR"
# ── Dirty Check ───────────────────────────────────────────────────────
if [ "$FORCE" = false ]; then
log "Running dirty checks..."
# Check for uncommitted changes
if ! git diff-index --quiet HEAD --; then
fail "Uncommitted changes detected. Commit or stash first, or use --force"
fi
# Check for untracked files
if [ -n "$(git ls-files --others --exclude-standard)" ]; then
fail "Untracked files detected. Commit or remove them, or use --force"
fi
# Check for unpushed commits
LOCAL_COMMIT=$(git rev-parse @)
REMOTE_COMMIT=$(git rev-parse '@{u}' 2>/dev/null || echo "")
if [ -n "$REMOTE_COMMIT" ] && [ "$LOCAL_COMMIT" != "$REMOTE_COMMIT" ]; then
fail "Unpushed commits detected. Push first or use --force"
fi
ok "Dirty checks passed"
else
warn "Skipping dirty checks (--force enabled)"
fi
# ── Pull and Rebase ───────────────────────────────────────────────────
log "Pulling latest changes from origin/main..."
git fetch origin
LOCAL_MAIN=$(git rev-parse main)
REMOTE_MAIN=$(git rev-parse origin/main)
if [ "$LOCAL_MAIN" != "$REMOTE_MAIN" ]; then
log "Local main is behind origin/main, rebasing..."
git rebase origin/main || {
fail "Rebase failed. Resolve conflicts and run: git rebase --continue"
}
ok "Rebase completed successfully"
else
ok "Already up to date with origin/main"
fi
# ── Run Smoke Tests ─────────────────────────────────────────────────────
if [ "$SKIP_HEALTH_CHECK" = false ]; then
log "Running smoke tests before deployment..."
if [ -f "scripts/smoke-release.sh" ]; then
chmod +x scripts/smoke-release.sh
./scripts/smoke-release.sh || {
fail "Smoke tests failed. Fix issues before deploying or use --skip-health-check"
}
ok "Smoke tests passed"
else
warn "Smoke test script not found, skipping pre-deployment tests"
fi
fi
# ── Build and Deploy ──────────────────────────────────────────────────
log "Building and deploying Docker containers..."
# Check if docker-compose files exist
if [ ! -f "docker-compose.yml" ]; then
fail "docker-compose.yml not found in $REPO_DIR"
fi
# Run docker-prep.sh to package dependencies
if [ -f "scripts/docker-prep.sh" ]; then
log "Running docker-prep.sh to package dependencies..."
chmod +x scripts/docker-prep.sh
./scripts/docker-prep.sh || fail "docker-prep.sh failed"
ok "Dependencies packaged successfully"
else
fail "docker-prep.sh not found in $REPO_DIR/scripts/"
fi
# Build and start services
log "Building Docker images..."
docker compose build || fail "Docker build failed"
log "Starting services..."
docker compose up -d || fail "Docker compose up failed"
ok "Deployment completed"
# ── Health Check ──────────────────────────────────────────────────────
if [ "$SKIP_HEALTH_CHECK" = true ]; then
warn "Skipping health checks (--skip-health-check enabled)"
exit 0
fi
log "Waiting for services to be healthy..."
sleep 10
# Check backend health
BACKEND_HEALTH=false
for _ in {1..30}; do
if curl -sf http://localhost:4011/health > /dev/null 2>&1; then
BACKEND_HEALTH=true
break
fi
echo -n "."
sleep 2
done
echo ""
if [ "$BACKEND_HEALTH" = true ]; then
ok "Backend health check passed (http://localhost:4011)"
else
fail "Backend health check failed"
fi
# Check web health
WEB_HEALTH=false
for _ in {1..30}; do
if curl -sf http://localhost:3030 > /dev/null 2>&1; then
WEB_HEALTH=true
break
fi
echo -n "."
sleep 2
done
echo ""
if [ "$WEB_HEALTH" = true ]; then
ok "Web health check passed (http://localhost:3030)"
else
warn "Web health check failed (may be starting up)"
fi
# ── Endpoint Verification ─────────────────────────────────────────────
log "Verifying production endpoints..."
API_ENDPOINT="https://api.bytelyst.com/chronomind"
WEB_ENDPOINT="http://localhost:3030"
# Check API endpoint
if curl -sf "$API_ENDPOINT/health" > /dev/null 2>&1; then
ok "API endpoint accessible: $API_ENDPOINT"
else
warn "API endpoint not accessible: $API_ENDPOINT (may need DNS propagation or routing)"
fi
# Check web endpoint
if curl -sf "$WEB_ENDPOINT" > /dev/null 2>&1; then
ok "Web endpoint accessible: $WEB_ENDPOINT"
else
warn "Web endpoint not accessible: $WEB_ENDPOINT (may be starting up)"
fi
# ── API Smoke Tests (Post-Deployment) ───────────────────────────────────
log "Running post-deployment API smoke tests..."
# Test backend health endpoint
BACKEND_URL="http://localhost:4011"
if curl -sf "$BACKEND_URL/health" > /dev/null 2>&1; then
ok "Backend health endpoint responding"
# Try to get health details
HEALTH_RESPONSE=$(curl -s "$BACKEND_URL/health" 2>/dev/null || echo "{}")
log "Health response: $HEALTH_RESPONSE"
else
fail "Backend health endpoint not responding"
fi
# Test web is serving content
WEB_URL="http://localhost:3030"
if curl -sf "$WEB_URL" > /dev/null 2>&1; then
ok "Web frontend is serving content"
# Check if it's actually HTML
CONTENT_TYPE=$(curl -sI "$WEB_URL" | grep -i content-type || echo "")
if echo "$CONTENT_TYPE" | grep -qi "text/html"; then
ok "Web frontend is serving HTML content"
else
warn "Web frontend content type unexpected: $CONTENT_TYPE"
fi
else
fail "Web frontend not responding"
fi
log "══════════════════════════════════════════════════════════════════════"
ok "Deployment completed successfully!"
log "Backend: http://localhost:4011 → $API_ENDPOINT"
log "Web: http://localhost:3030"
log "══════════════════════════════════════════════════════════════════════"

View File

@ -1,223 +0,0 @@
#!/usr/bin/env bash
set -euo pipefail
# ═══════════════════════════════════════════════════════════════════════
# ByteLyst Investment Trading - Production Deployment Script
# ═══════════════════════════════════════════════════════════════════════
# Usage: ./deploy-invttrdg.sh [--force] [--skip-health-check]
#
# What it does:
# 1. Dirty check: uncommitted changes, unpushed commits
# 2. Pull and rebase origin/main
# 3. Build and deploy Docker containers
# 4. Verify endpoints: https://api.bytelyst.com/invttrdg, https://invttrdg.bytelyst.com
#
# Options:
# --force Skip dirty checks and force deployment
# --skip-health-check Skip endpoint health verification
# ═══════════════════════════════════════════════════════════════════════
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; CYAN='\033[0;36m'; NC='\033[0m'
log() { echo -e "${CYAN}[$(date +%H:%M:%S)]${NC} $*"; }
ok() { echo -e "${GREEN}[$(date +%H:%M:%S)] ✓${NC} $*"; }
warn() { echo -e "${YELLOW}[$(date +%H:%M:%S)] ⚠${NC} $*"; }
fail() { echo -e "${RED}[$(date +%H:%M:%S)] ✗${NC} $*"; exit 1; }
# ── Configuration ────────────────────────────────────────────────────
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
REPO_DIR="${SCRIPT_DIR}/../learning_ai_invt_trdg"
cd "$SCRIPT_DIR"
FORCE=false
SKIP_HEALTH_CHECK=false
while [[ $# -gt 0 ]]; do
case "$1" in
--force) FORCE=true; shift ;;
--skip-health-check) SKIP_HEALTH_CHECK=true; shift ;;
*) fail "Unknown option: $1" ;;
esac
done
# ── Prerequisites ────────────────────────────────────────────────────
if [ ! -d "$REPO_DIR" ]; then
fail "Repo directory not found: $REPO_DIR"
fi
cd "$REPO_DIR"
# ── Dirty Check ───────────────────────────────────────────────────────
if [ "$FORCE" = false ]; then
log "Running dirty checks..."
# Check for uncommitted changes
if ! git diff-index --quiet HEAD --; then
fail "Uncommitted changes detected. Commit or stash first, or use --force"
fi
# Check for untracked files
if [ -n "$(git ls-files --others --exclude-standard)" ]; then
fail "Untracked files detected. Commit or remove them, or use --force"
fi
# Check for unpushed commits
LOCAL_COMMIT=$(git rev-parse @)
REMOTE_COMMIT=$(git rev-parse '@{u}' 2>/dev/null || echo "")
if [ -n "$REMOTE_COMMIT" ] && [ "$LOCAL_COMMIT" != "$REMOTE_COMMIT" ]; then
fail "Unpushed commits detected. Push first or use --force"
fi
ok "Dirty checks passed"
else
warn "Skipping dirty checks (--force enabled)"
fi
# ── Pull and Rebase ───────────────────────────────────────────────────
log "Pulling latest changes from origin/main..."
git fetch origin
LOCAL_MAIN=$(git rev-parse main)
REMOTE_MAIN=$(git rev-parse origin/main)
if [ "$LOCAL_MAIN" != "$REMOTE_MAIN" ]; then
log "Local main is behind origin/main, rebasing..."
git rebase origin/main || {
fail "Rebase failed. Resolve conflicts and run: git rebase --continue"
}
ok "Rebase completed successfully"
else
ok "Already up to date with origin/main"
fi
# ── Run Smoke Tests ─────────────────────────────────────────────────────
if [ "$SKIP_HEALTH_CHECK" = false ]; then
log "Running smoke tests before deployment..."
if [ -f "scripts/smoke-release.sh" ]; then
chmod +x scripts/smoke-release.sh
./scripts/smoke-release.sh || {
fail "Smoke tests failed. Fix issues before deploying or use --skip-health-check"
}
ok "Smoke tests passed"
else
warn "Smoke test script not found, skipping pre-deployment tests"
fi
fi
# ── Build and Deploy ──────────────────────────────────────────────────
log "Building and deploying Docker containers..."
# Check if docker-compose files exist
if [ ! -f "docker-compose.yml" ]; then
fail "docker-compose.yml not found in $REPO_DIR"
fi
# Build and start services
log "Building Docker images..."
docker compose build || fail "Docker build failed"
log "Starting services..."
docker compose up -d || fail "Docker compose up failed"
ok "Deployment completed"
# ── Health Check ──────────────────────────────────────────────────────
if [ "$SKIP_HEALTH_CHECK" = true ]; then
warn "Skipping health checks (--skip-health-check enabled)"
exit 0
fi
log "Waiting for services to be healthy..."
sleep 10
# Check backend health
BACKEND_HEALTH=false
for _ in {1..30}; do
if curl -sf http://localhost:4025/health/live > /dev/null 2>&1; then
BACKEND_HEALTH=true
break
fi
echo -n "."
sleep 2
done
echo ""
if [ "$BACKEND_HEALTH" = true ]; then
ok "Backend health check passed (http://localhost:4025)"
else
fail "Backend health check failed"
fi
# Check web health
WEB_HEALTH=false
for _ in {1..30}; do
if curl -sf http://localhost:3085 > /dev/null 2>&1; then
WEB_HEALTH=true
break
fi
echo -n "."
sleep 2
done
echo ""
if [ "$WEB_HEALTH" = true ]; then
ok "Web health check passed (http://localhost:3085)"
else
warn "Web health check failed (may be starting up)"
fi
# ── Endpoint Verification ─────────────────────────────────────────────
log "Verifying production endpoints..."
API_ENDPOINT="https://api.bytelyst.com/invttrdg"
WEB_ENDPOINT="https://invttrdg.bytelyst.com"
# Check API endpoint
if curl -sf "$API_ENDPOINT/health/live" > /dev/null 2>&1; then
ok "API endpoint accessible: $API_ENDPOINT"
else
warn "API endpoint not accessible: $API_ENDPOINT (may need DNS propagation)"
fi
# Check web endpoint
if curl -sf "$WEB_ENDPOINT" > /dev/null 2>&1; then
ok "Web endpoint accessible: $WEB_ENDPOINT"
else
warn "Web endpoint not accessible: $WEB_ENDPOINT (may need DNS propagation)"
fi
# ── API Smoke Tests (Post-Deployment) ───────────────────────────────────
log "Running post-deployment API smoke tests..."
# Test backend health endpoint
BACKEND_URL="http://localhost:4025"
if curl -sf "$BACKEND_URL/health/live" > /dev/null 2>&1; then
ok "Backend health endpoint responding"
# Try to get health details
HEALTH_RESPONSE=$(curl -s "$BACKEND_URL/health/live" 2>/dev/null || echo "{}")
log "Health response: $HEALTH_RESPONSE"
else
fail "Backend health endpoint not responding"
fi
# Test web is serving content
WEB_URL="http://localhost:3085"
if curl -sf "$WEB_URL" > /dev/null 2>&1; then
ok "Web frontend is serving content"
# Check if it's actually HTML (nginx serving the SPA)
CONTENT_TYPE=$(curl -sI "$WEB_URL" | grep -i content-type || echo "")
if echo "$CONTENT_TYPE" | grep -qi "text/html"; then
ok "Web frontend is serving HTML content"
else
warn "Web frontend content type unexpected: $CONTENT_TYPE"
fi
else
fail "Web frontend not responding"
fi
log "══════════════════════════════════════════════════════════════════════"
ok "Deployment completed successfully!"
log "Backend: http://localhost:4025 → $API_ENDPOINT"
log "Web: http://localhost:3085 → $WEB_ENDPOINT"
log "══════════════════════════════════════════════════════════════════════"

View File

@ -1,233 +0,0 @@
#!/usr/bin/env bash
set -euo pipefail
# ═══════════════════════════════════════════════════════════════════════
# ByteLyst NoteLett - Production Deployment Script
# ═══════════════════════════════════════════════════════════════════════
# Usage: ./deploy-notes.sh [--force] [--skip-health-check]
#
# What it does:
# 1. Dirty check: uncommitted changes, unpushed commits
# 2. Pull and rebase origin/main
# 3. Build and deploy Docker containers
# 4. Verify endpoints: https://api.bytelyst.com/notelett, http://localhost:3000
#
# Options:
# --force Skip dirty checks and force deployment
# --skip-health-check Skip endpoint health verification
# ═══════════════════════════════════════════════════════════════════════
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; CYAN='\033[0;36m'; NC='\033[0m'
log() { echo -e "${CYAN}[$(date +%H:%M:%S)]${NC} $*"; }
ok() { echo -e "${GREEN}[$(date +%H:%M:%S)] ✓${NC} $*"; }
warn() { echo -e "${YELLOW}[$(date +%H:%M:%S)] ⚠${NC} $*"; }
fail() { echo -e "${RED}[$(date +%H:%M:%S)] ✗${NC} $*"; exit 1; }
# ── Configuration ────────────────────────────────────────────────────
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
REPO_DIR="${SCRIPT_DIR}/../learning_ai_notes"
cd "$SCRIPT_DIR"
FORCE=false
SKIP_HEALTH_CHECK=false
while [[ $# -gt 0 ]]; do
case "$1" in
--force) FORCE=true; shift ;;
--skip-health-check) SKIP_HEALTH_CHECK=true; shift ;;
*) fail "Unknown option: $1" ;;
esac
done
# ── Prerequisites ────────────────────────────────────────────────────
if [ ! -d "$REPO_DIR" ]; then
fail "Repo directory not found: $REPO_DIR"
fi
cd "$REPO_DIR"
# ── Dirty Check ───────────────────────────────────────────────────────
if [ "$FORCE" = false ]; then
log "Running dirty checks..."
# Check for uncommitted changes
if ! git diff-index --quiet HEAD --; then
fail "Uncommitted changes detected. Commit or stash first, or use --force"
fi
# Check for untracked files
if [ -n "$(git ls-files --others --exclude-standard)" ]; then
fail "Untracked files detected. Commit or remove them, or use --force"
fi
# Check for unpushed commits
LOCAL_COMMIT=$(git rev-parse @)
REMOTE_COMMIT=$(git rev-parse '@{u}' 2>/dev/null || echo "")
if [ -n "$REMOTE_COMMIT" ] && [ "$LOCAL_COMMIT" != "$REMOTE_COMMIT" ]; then
fail "Unpushed commits detected. Push first or use --force"
fi
ok "Dirty checks passed"
else
warn "Skipping dirty checks (--force enabled)"
fi
# ── Pull and Rebase ───────────────────────────────────────────────────
log "Pulling latest changes from origin/main..."
git fetch origin
LOCAL_MAIN=$(git rev-parse main)
REMOTE_MAIN=$(git rev-parse origin/main)
if [ "$LOCAL_MAIN" != "$REMOTE_MAIN" ]; then
log "Local main is behind origin/main, rebasing..."
git rebase origin/main || {
fail "Rebase failed. Resolve conflicts and run: git rebase --continue"
}
ok "Rebase completed successfully"
else
ok "Already up to date with origin/main"
fi
# ── Run Smoke Tests ─────────────────────────────────────────────────────
if [ "$SKIP_HEALTH_CHECK" = false ]; then
log "Running smoke tests before deployment..."
if [ -f "scripts/smoke-release.sh" ]; then
chmod +x scripts/smoke-release.sh
./scripts/smoke-release.sh || {
fail "Smoke tests failed. Fix issues before deploying or use --skip-health-check"
}
ok "Smoke tests passed"
else
warn "Smoke test script not found, skipping pre-deployment tests"
fi
fi
# ── Build and Deploy ──────────────────────────────────────────────────
log "Building and deploying Docker containers..."
# Check if docker-compose files exist
if [ ! -f "docker-compose.yml" ]; then
fail "docker-compose.yml not found in $REPO_DIR"
fi
# Run docker-prep.sh to package dependencies
if [ -f "scripts/docker-prep.sh" ]; then
log "Running docker-prep.sh to package dependencies..."
chmod +x scripts/docker-prep.sh
./scripts/docker-prep.sh || fail "docker-prep.sh failed"
ok "Dependencies packaged successfully"
else
fail "docker-prep.sh not found in $REPO_DIR/scripts/"
fi
# Build and start services
log "Building Docker images..."
docker compose build || fail "Docker build failed"
log "Starting services..."
docker compose up -d || fail "Docker compose up failed"
ok "Deployment completed"
# ── Health Check ──────────────────────────────────────────────────────
if [ "$SKIP_HEALTH_CHECK" = true ]; then
warn "Skipping health checks (--skip-health-check enabled)"
exit 0
fi
log "Waiting for services to be healthy..."
sleep 10
# Check backend health
BACKEND_HEALTH=false
for _ in {1..30}; do
if curl -sf http://localhost:4016/health > /dev/null 2>&1; then
BACKEND_HEALTH=true
break
fi
echo -n "."
sleep 2
done
echo ""
if [ "$BACKEND_HEALTH" = true ]; then
ok "Backend health check passed (http://localhost:4016)"
else
fail "Backend health check failed"
fi
# Check web health
WEB_HEALTH=false
for _ in {1..30}; do
if curl -sf http://localhost:3000 > /dev/null 2>&1; then
WEB_HEALTH=true
break
fi
echo -n "."
sleep 2
done
echo ""
if [ "$WEB_HEALTH" = true ]; then
ok "Web health check passed (http://localhost:3000)"
else
warn "Web health check failed (may be starting up)"
fi
# ── Endpoint Verification ─────────────────────────────────────────────
log "Verifying production endpoints..."
API_ENDPOINT="https://api.bytelyst.com/notelett"
WEB_ENDPOINT="http://localhost:3000"
# Check API endpoint
if curl -sf "$API_ENDPOINT/health" > /dev/null 2>&1; then
ok "API endpoint accessible: $API_ENDPOINT"
else
warn "API endpoint not accessible: $API_ENDPOINT (may need DNS propagation or routing)"
fi
# Check web endpoint
if curl -sf "$WEB_ENDPOINT" > /dev/null 2>&1; then
ok "Web endpoint accessible: $WEB_ENDPOINT"
else
warn "Web endpoint not accessible: $WEB_ENDPOINT (may be starting up)"
fi
# ── API Smoke Tests (Post-Deployment) ───────────────────────────────────
log "Running post-deployment API smoke tests..."
# Test backend health endpoint
BACKEND_URL="http://localhost:4016"
if curl -sf "$BACKEND_URL/health" > /dev/null 2>&1; then
ok "Backend health endpoint responding"
# Try to get health details
HEALTH_RESPONSE=$(curl -s "$BACKEND_URL/health" 2>/dev/null || echo "{}")
log "Health response: $HEALTH_RESPONSE"
else
fail "Backend health endpoint not responding"
fi
# Test web is serving content
WEB_URL="http://localhost:3000"
if curl -sf "$WEB_URL" > /dev/null 2>&1; then
ok "Web frontend is serving content"
# Check if it's actually HTML
CONTENT_TYPE=$(curl -sI "$WEB_URL" | grep -i content-type || echo "")
if echo "$CONTENT_TYPE" | grep -qi "text/html"; then
ok "Web frontend is serving HTML content"
else
warn "Web frontend content type unexpected: $CONTENT_TYPE"
fi
else
fail "Web frontend not responding"
fi
log "══════════════════════════════════════════════════════════════════════"
ok "Deployment completed successfully!"
log "Backend: http://localhost:4016 → $API_ENDPOINT"
log "Web: http://localhost:3000"
log "══════════════════════════════════════════════════════════════════════"