feat: complete monorepo structure with frontend and shared resources

- Add complete backend/ directory with full Django application
- Add frontend/ directory with Vite + TypeScript setup ready for Next.js
- Add comprehensive shared/ directory with:
  - Complete documentation and memory-bank archives
  - Media files and avatars (letters, park/ride images)
  - Deployment scripts and automation tools
  - Shared types and utilities
- Add architecture/ directory with migration guides
- Configure pnpm workspace for monorepo development
- Update .gitignore to exclude .django_tailwind_cli/ build artifacts
- Preserve all historical documentation in shared/docs/memory-bank/
- Set up proper structure for full-stack development with shared resources
This commit is contained in:
pacnpal
2025-08-23 18:40:07 -04:00
parent b0e0678590
commit d504d41de2
762 changed files with 142636 additions and 0 deletions

340
shared/scripts/vm-deploy.sh Executable file
View File

@@ -0,0 +1,340 @@
#!/bin/bash
# ThrillWiki VM Deployment Script
# This script runs on the Linux VM to deploy the latest code and restart the server
set -e # Exit on any error
# Configuration
PROJECT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
LOG_DIR="$PROJECT_DIR/logs"
BACKUP_DIR="$PROJECT_DIR/backups"
DEPLOY_LOG="$LOG_DIR/deploy.log"
SERVICE_NAME="thrillwiki"
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Logging function
log() {
local message="[$(date +'%Y-%m-%d %H:%M:%S')] $1"
echo -e "${BLUE}${message}${NC}"
echo "$message" >> "$DEPLOY_LOG"
}
log_success() {
local message="[$(date +'%Y-%m-%d %H:%M:%S')] ✓ $1"
echo -e "${GREEN}${message}${NC}"
echo "$message" >> "$DEPLOY_LOG"
}
log_warning() {
local message="[$(date +'%Y-%m-%d %H:%M:%S')] ⚠ $1"
echo -e "${YELLOW}${message}${NC}"
echo "$message" >> "$DEPLOY_LOG"
}
log_error() {
local message="[$(date +'%Y-%m-%d %H:%M:%S')] ✗ $1"
echo -e "${RED}${message}${NC}"
echo "$message" >> "$DEPLOY_LOG"
}
# Create necessary directories
create_directories() {
log "Creating necessary directories..."
mkdir -p "$LOG_DIR" "$BACKUP_DIR"
log_success "Directories created"
}
# Backup current deployment
backup_current() {
log "Creating backup of current deployment..."
local timestamp=$(date +'%Y%m%d_%H%M%S')
local backup_path="$BACKUP_DIR/backup_$timestamp"
# Create backup of current code
if [ -d "$PROJECT_DIR/.git" ]; then
local current_commit=$(git -C "$PROJECT_DIR" rev-parse HEAD)
echo "$current_commit" > "$backup_path.commit"
log_success "Backup created with commit: ${current_commit:0:8}"
else
log_warning "Not a git repository, skipping backup"
fi
}
# Stop the service
stop_service() {
log "Stopping ThrillWiki service..."
# Stop systemd service if it exists
if systemctl is-active --quiet "$SERVICE_NAME" 2>/dev/null; then
sudo systemctl stop "$SERVICE_NAME"
log_success "Systemd service stopped"
else
log "Systemd service not running"
fi
# Kill any remaining Django processes on port 8000
if lsof -ti :8000 >/dev/null 2>&1; then
log "Stopping processes on port 8000..."
lsof -ti :8000 | xargs kill -9 2>/dev/null || true
log_success "Port 8000 processes stopped"
fi
# Clean up Python cache
log "Cleaning Python cache..."
find "$PROJECT_DIR" -type d -name "__pycache__" -exec rm -r {} + 2>/dev/null || true
log_success "Python cache cleaned"
}
# Update code from git
update_code() {
log "Updating code from git repository..."
cd "$PROJECT_DIR"
# Fetch latest changes
git fetch origin
log "Fetched latest changes"
# Get current and new commit info
local old_commit=$(git rev-parse HEAD)
local new_commit=$(git rev-parse origin/main)
if [ "$old_commit" = "$new_commit" ]; then
log_warning "No new commits to deploy"
return 0
fi
log "Updating from ${old_commit:0:8} to ${new_commit:0:8}"
# Pull latest changes
git reset --hard origin/main
log_success "Code updated successfully"
# Show what changed
log "Changes in this deployment:"
git log --oneline "$old_commit..$new_commit" || true
}
# Install/update dependencies
update_dependencies() {
log "Updating dependencies..."
cd "$PROJECT_DIR"
# Check if UV is installed
if ! command -v uv &> /dev/null; then
log_error "UV is not installed. Installing UV..."
curl -LsSf https://astral.sh/uv/install.sh | sh
source $HOME/.cargo/env
fi
# Sync dependencies
uv sync --no-dev || {
log_error "Failed to sync dependencies"
return 1
}
log_success "Dependencies updated"
}
# Run database migrations
run_migrations() {
log "Running database migrations..."
cd "$PROJECT_DIR"
# Check for pending migrations
if uv run manage.py showmigrations --plan | grep -q "\[ \]"; then
log "Applying database migrations..."
uv run manage.py migrate || {
log_error "Database migrations failed"
return 1
}
log_success "Database migrations completed"
else
log "No pending migrations"
fi
}
# Collect static files
collect_static() {
log "Collecting static files..."
cd "$PROJECT_DIR"
uv run manage.py collectstatic --noinput || {
log_warning "Static file collection failed, continuing..."
}
log_success "Static files collected"
}
# Start the service
start_service() {
log "Starting ThrillWiki service..."
cd "$PROJECT_DIR"
# Start systemd service if it exists
if systemctl list-unit-files | grep -q "^$SERVICE_NAME.service"; then
sudo systemctl start "$SERVICE_NAME"
sudo systemctl enable "$SERVICE_NAME"
# Wait for service to start
sleep 5
if systemctl is-active --quiet "$SERVICE_NAME"; then
log_success "Systemd service started successfully"
else
log_error "Systemd service failed to start"
return 1
fi
else
log_warning "Systemd service not found, starting manually..."
# Start server in background
nohup ./scripts/ci-start.sh > "$LOG_DIR/server.log" 2>&1 &
local server_pid=$!
# Wait for server to start
sleep 5
if kill -0 $server_pid 2>/dev/null; then
echo $server_pid > "$LOG_DIR/server.pid"
log_success "Server started manually with PID: $server_pid"
else
log_error "Failed to start server manually"
return 1
fi
fi
}
# Health check
health_check() {
log "Performing health check..."
local max_attempts=30
local attempt=1
while [ $attempt -le $max_attempts ]; do
if curl -f -s http://localhost:8000/health >/dev/null 2>&1; then
log_success "Health check passed"
return 0
fi
log "Health check attempt $attempt/$max_attempts failed, retrying..."
sleep 2
((attempt++))
done
log_error "Health check failed after $max_attempts attempts"
return 1
}
# Cleanup old backups
cleanup_backups() {
log "Cleaning up old backups..."
# Keep only the last 10 backups
cd "$BACKUP_DIR"
ls -t backup_*.commit 2>/dev/null | tail -n +11 | xargs rm -f 2>/dev/null || true
log_success "Old backups cleaned up"
}
# Rollback function
rollback() {
log_error "Deployment failed, attempting rollback..."
local latest_backup=$(ls -t "$BACKUP_DIR"/backup_*.commit 2>/dev/null | head -n 1)
if [ -n "$latest_backup" ]; then
local backup_commit=$(cat "$latest_backup")
log "Rolling back to commit: ${backup_commit:0:8}"
cd "$PROJECT_DIR"
git reset --hard "$backup_commit"
# Restart service
stop_service
start_service
if health_check; then
log_success "Rollback completed successfully"
else
log_error "Rollback failed - manual intervention required"
fi
else
log_error "No backup found for rollback"
fi
}
# Main deployment function
deploy() {
log "=== ThrillWiki Deployment Started ==="
log "Timestamp: $(date)"
log "User: $(whoami)"
log "Host: $(hostname)"
# Trap errors for rollback
trap rollback ERR
create_directories
backup_current
stop_service
update_code
update_dependencies
run_migrations
collect_static
start_service
health_check
cleanup_backups
# Remove error trap
trap - ERR
log_success "=== Deployment Completed Successfully ==="
log "Server is now running the latest code"
log "Check logs at: $LOG_DIR/"
}
# Script execution
case "${1:-deploy}" in
deploy)
deploy
;;
stop)
stop_service
;;
start)
start_service
;;
restart)
stop_service
start_service
health_check
;;
status)
if systemctl is-active --quiet "$SERVICE_NAME" 2>/dev/null; then
echo "Service is running"
elif [ -f "$LOG_DIR/server.pid" ] && kill -0 "$(cat "$LOG_DIR/server.pid")" 2>/dev/null; then
echo "Server is running manually"
else
echo "Service is not running"
fi
;;
health)
health_check
;;
*)
echo "Usage: $0 {deploy|stop|start|restart|status|health}"
exit 1
;;
esac