Full app audit: 24 fixes across backend, frontend, infra, content, social

Critical fixes:
- Fix hangup-during-respond crash (null caller guard)
- Fix double-click caller race condition
- Stem recorder: non-daemon thread, disk error handling, 30s flush timeout
- Frontend startCall() error handling

High priority:
- Devon: filter tool errors from speech, shorter monitor prompt, 30s interval
- TTS ghost message fix (add to history after TTS, not before)
- Expand banned phrase list (12 new phrases)
- Increase returning callers from 1 to 2 per session
- Platform-tailored social posts with staggered scheduling
- YouTube dynamic tags from episode content
- Social post retry logic (2 attempts, 5s delay)
- Frontend: error handling on all raw fetch calls

Medium:
- stem_recorder null check race (local var capture in audio.py)
- Reactive shape directive expanded
- REACT TO LUKE moved higher in caller prompt
- Devon tenure updated ("few weeks" not "first day")
- D shortcut Escape to unfocus
- Volume slider debounced (150ms)
- Settings modal widened to 550px
- Backup script (daily MariaDB dump + data/ rsync to NAS)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-18 14:57:50 -06:00
parent 5e98ed0e11
commit 3dd6a83c68
9 changed files with 492 additions and 188 deletions
Executable
+58
View File
@@ -0,0 +1,58 @@
#!/bin/bash
# Daily backup of critical AI podcast data to NAS
# Backs up: Castopod MariaDB dump, local data/ directory, publish state
#
# Usage: ./backup.sh
# Cron: 0 3 * * * /Users/lukemacneil/code/ai-podcast/backup.sh >> /tmp/ai-podcast-backup.log 2>&1
set -euo pipefail
NAS_HOST="mmgnas"
NAS_USER="luke"
NAS_PORT="8001"
DOCKER_BIN="/share/CACHEDEV1_DATA/.qpkg/container-station/bin/docker"
BACKUP_BASE="/share/CACHEDEV1_DATA/backups/ai-podcast"
PROJECT_DIR="/Users/lukemacneil/code/ai-podcast"
DATE=$(date +%Y-%m-%d)
KEEP_DAYS=14
echo "$(date -u '+%Y-%m-%dT%H:%M:%SZ') Starting backup..."
# 1. Dump Castopod MariaDB on NAS
echo " Dumping MariaDB..."
ssh -p "$NAS_PORT" "$NAS_USER@$NAS_HOST" \
"$DOCKER_BIN exec castopod-mariadb-1 mysqldump -u castopod --password=\$(cat /run/secrets/db_password 2>/dev/null || echo BYtbFfk3ndeVabb26xb0UyKU) castopod" \
> "/tmp/castopod-db-${DATE}.sql" 2>/dev/null
if [ -s "/tmp/castopod-db-${DATE}.sql" ]; then
gzip -f "/tmp/castopod-db-${DATE}.sql"
scp -P "$NAS_PORT" "/tmp/castopod-db-${DATE}.sql.gz" \
"$NAS_USER@$NAS_HOST:$BACKUP_BASE/castopod-db-${DATE}.sql.gz"
rm -f "/tmp/castopod-db-${DATE}.sql.gz"
echo " MariaDB dump: OK"
else
echo " WARNING: MariaDB dump is empty or failed"
fi
# 2. Sync data/ directory to NAS (rsync for efficiency)
echo " Syncing data/ directory..."
rsync -az --delete \
-e "ssh -p $NAS_PORT" \
"$PROJECT_DIR/data/" \
"$NAS_USER@$NAS_HOST:$BACKUP_BASE/data/"
echo " data/ sync: OK"
# 3. Backup .env (contains API keys — critical for disaster recovery)
echo " Backing up .env..."
scp -P "$NAS_PORT" "$PROJECT_DIR/.env" \
"$NAS_USER@$NAS_HOST:$BACKUP_BASE/env-${DATE}.bak"
echo " .env backup: OK"
# 4. Prune old backups
echo " Pruning backups older than ${KEEP_DAYS} days..."
ssh -p "$NAS_PORT" "$NAS_USER@$NAS_HOST" \
"find $BACKUP_BASE -name 'castopod-db-*.sql.gz' -mtime +${KEEP_DAYS} -delete 2>/dev/null; \
find $BACKUP_BASE -name 'env-*.bak' -mtime +${KEEP_DAYS} -delete 2>/dev/null"
echo " Prune: OK"
echo "$(date -u '+%Y-%m-%dT%H:%M:%SZ') Backup complete."