Refactor deployment documentation for ScriptShare, consolidating deployment guides into a single comprehensive document while removing outdated Docker deployment files and scripts. Enhance clarity on deployment options across various platforms and streamline the application structure overview.
This commit is contained in:
65
.github/workflows/build.yml
vendored
Normal file
65
.github/workflows/build.yml
vendored
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
name: Build and Test
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ main, develop ]
|
||||||
|
pull_request:
|
||||||
|
branches: [ main ]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup Node.js
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: '18'
|
||||||
|
cache: 'npm'
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: npm ci
|
||||||
|
|
||||||
|
- name: Run linting
|
||||||
|
run: npm run lint
|
||||||
|
|
||||||
|
- name: Build frontend
|
||||||
|
run: npm run build
|
||||||
|
|
||||||
|
- name: Build API
|
||||||
|
run: npm run build:api
|
||||||
|
|
||||||
|
docker-build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: test
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v3
|
||||||
|
|
||||||
|
- name: Build frontend Docker image
|
||||||
|
uses: docker/build-push-action@v5
|
||||||
|
with:
|
||||||
|
context: .
|
||||||
|
file: ./Dockerfile
|
||||||
|
push: false
|
||||||
|
tags: scriptshare-frontend:latest
|
||||||
|
|
||||||
|
- name: Build API Docker image
|
||||||
|
uses: docker/build-push-action@v5
|
||||||
|
with:
|
||||||
|
context: .
|
||||||
|
file: ./Dockerfile.api
|
||||||
|
push: false
|
||||||
|
tags: scriptshare-api:latest
|
||||||
|
|
||||||
|
- name: Test Docker containers
|
||||||
|
run: |
|
||||||
|
# Test that images were built successfully
|
||||||
|
docker images | grep scriptshare
|
102
.github/workflows/deploy.yml
vendored
102
.github/workflows/deploy.yml
vendored
@ -1,102 +0,0 @@
|
|||||||
name: Deploy to DigitalOcean
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: [ main ]
|
|
||||||
pull_request:
|
|
||||||
branches: [ main ]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
# Test job to run before deployment
|
|
||||||
test:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Setup Node.js
|
|
||||||
uses: actions/setup-node@v4
|
|
||||||
with:
|
|
||||||
node-version: '18'
|
|
||||||
cache: 'npm'
|
|
||||||
|
|
||||||
- name: Install dependencies
|
|
||||||
run: npm ci
|
|
||||||
|
|
||||||
- name: Run linter
|
|
||||||
run: npm run lint
|
|
||||||
|
|
||||||
- name: Build frontend
|
|
||||||
run: npm run build
|
|
||||||
env:
|
|
||||||
VITE_APP_NAME: ScriptShare
|
|
||||||
VITE_APP_URL: https://scriptshare.example.com
|
|
||||||
VITE_ANALYTICS_ENABLED: true
|
|
||||||
|
|
||||||
# Deploy job (only on main branch)
|
|
||||||
deploy:
|
|
||||||
needs: test
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Install doctl
|
|
||||||
uses: digitalocean/action-doctl@v2
|
|
||||||
with:
|
|
||||||
token: ${{ secrets.DIGITALOCEAN_ACCESS_TOKEN }}
|
|
||||||
|
|
||||||
- name: Get app info
|
|
||||||
id: app-info
|
|
||||||
run: |
|
|
||||||
APP_ID=$(doctl apps list --format ID,Spec.Name --no-header | grep scriptshare | cut -d' ' -f1)
|
|
||||||
echo "app-id=$APP_ID" >> $GITHUB_OUTPUT
|
|
||||||
|
|
||||||
- name: Trigger deployment
|
|
||||||
run: |
|
|
||||||
doctl apps create-deployment ${{ steps.app-info.outputs.app-id }} --wait
|
|
||||||
|
|
||||||
- name: Run database migrations
|
|
||||||
run: |
|
|
||||||
# Wait for deployment to complete
|
|
||||||
sleep 60
|
|
||||||
|
|
||||||
# Run migrations via the app console (if needed)
|
|
||||||
echo "Deployment completed. Please run database migrations manually if this is the first deployment."
|
|
||||||
echo "Command: npm run db:setup:prod"
|
|
||||||
|
|
||||||
# Database migration job (manual trigger)
|
|
||||||
migrate:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
if: github.event_name == 'workflow_dispatch'
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Setup Node.js
|
|
||||||
uses: actions/setup-node@v4
|
|
||||||
with:
|
|
||||||
node-version: '18'
|
|
||||||
cache: 'npm'
|
|
||||||
|
|
||||||
- name: Install dependencies
|
|
||||||
run: npm ci
|
|
||||||
|
|
||||||
- name: Run migrations
|
|
||||||
run: npm run db:migrate:prod
|
|
||||||
env:
|
|
||||||
DATABASE_URL: ${{ secrets.DATABASE_URL }}
|
|
||||||
|
|
||||||
# Manual workflow dispatch for running migrations
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
inputs:
|
|
||||||
action:
|
|
||||||
description: 'Action to perform'
|
|
||||||
required: true
|
|
||||||
default: 'migrate'
|
|
||||||
type: choice
|
|
||||||
options:
|
|
||||||
- migrate
|
|
||||||
- setup
|
|
407
DEPLOYMENT.md
407
DEPLOYMENT.md
@ -1,248 +1,261 @@
|
|||||||
# DigitalOcean Deployment Guide
|
# 🚀 ScriptShare - Platform Deployment Guide
|
||||||
|
|
||||||
This guide walks you through deploying ScriptShare to DigitalOcean App Platform with a managed MySQL database.
|
## Overview
|
||||||
|
|
||||||
## Prerequisites
|
ScriptShare is a modern React application with a Node.js API backend, designed to work seamlessly with any deployment platform including **Vercel**, **Coolify**, **DigitalOcean App Platform**, **Railway**, **Render**, and others.
|
||||||
|
|
||||||
- DigitalOcean account
|
## 📦 Application Structure
|
||||||
- GitHub repository containing your code
|
|
||||||
- Basic familiarity with DigitalOcean App Platform
|
|
||||||
|
|
||||||
## Architecture Overview
|
### Frontend (React + Vite)
|
||||||
|
- **Dockerfile**: `Dockerfile`
|
||||||
|
- **Build**: Vite-based React application
|
||||||
|
- **Output**: Static files served by Nginx
|
||||||
|
- **Port**: 80
|
||||||
|
|
||||||
The deployment consists of:
|
### Backend API (Node.js + Express)
|
||||||
- **Frontend**: Static site (React/Vite build)
|
- **Dockerfile**: `Dockerfile.api`
|
||||||
- **Backend API**: Node.js service with Express
|
- **Runtime**: Node.js 18 with TypeScript
|
||||||
- **Database**: DigitalOcean Managed MySQL Database
|
- **Port**: 3000
|
||||||
|
- **Health Check**: `/api/health`
|
||||||
|
|
||||||
## Step 1: Prepare Your Repository
|
## 🔧 Deployment Options
|
||||||
|
|
||||||
1. Ensure all the deployment files are in your GitHub repository:
|
### Option 1: Vercel (Recommended for Frontend)
|
||||||
|
|
||||||
|
**Frontend Deployment:**
|
||||||
|
1. Connect your repository to Vercel
|
||||||
|
2. Set build command: `npm run build`
|
||||||
|
3. Set output directory: `dist`
|
||||||
|
4. Configure environment variables:
|
||||||
```
|
```
|
||||||
.do/app.yaml # App Platform configuration
|
VITE_APP_NAME=ScriptShare
|
||||||
Dockerfile.api # Backend API container
|
VITE_APP_URL=https://your-domain.vercel.app
|
||||||
drizzle.config.production.ts # Production DB config
|
VITE_ANALYTICS_ENABLED=true
|
||||||
scripts/migrate-production.js # Migration script
|
|
||||||
scripts/setup-production-db.js # DB setup script
|
|
||||||
env.production.example # Environment variables template
|
|
||||||
```
|
```
|
||||||
|
|
||||||
2. Commit and push all changes to your main branch.
|
**API Deployment:**
|
||||||
|
- Deploy API separately to platforms like Railway, Render, or DigitalOcean
|
||||||
|
- Or use Vercel Functions (requires code modification)
|
||||||
|
|
||||||
## Step 2: Create the DigitalOcean App
|
### Option 2: Coolify (Full Stack)
|
||||||
|
|
||||||
### Option A: Using the DigitalOcean Console
|
**Deploy both frontend and API:**
|
||||||
|
1. Create application from Git repository
|
||||||
|
2. **Frontend**:
|
||||||
|
- Use `Dockerfile`
|
||||||
|
- Port: 80
|
||||||
|
3. **API**:
|
||||||
|
- Use `Dockerfile.api`
|
||||||
|
- Port: 3000
|
||||||
|
4. Configure environment variables
|
||||||
|
|
||||||
1. Go to the [DigitalOcean App Platform](https://cloud.digitalocean.com/apps)
|
### Option 3: DigitalOcean App Platform
|
||||||
2. Click **"Create App"**
|
|
||||||
3. Choose **"GitHub"** as your source
|
|
||||||
4. Select your repository and branch (usually `main`)
|
|
||||||
5. DigitalOcean will automatically detect the `app.yaml` configuration
|
|
||||||
|
|
||||||
### Option B: Using the CLI
|
Create `app.yaml`:
|
||||||
|
```yaml
|
||||||
|
name: scriptshare
|
||||||
|
services:
|
||||||
|
- name: frontend
|
||||||
|
source_dir: /
|
||||||
|
dockerfile_path: Dockerfile
|
||||||
|
github:
|
||||||
|
repo: your-username/scriptshare-cursor
|
||||||
|
branch: main
|
||||||
|
http_port: 80
|
||||||
|
routes:
|
||||||
|
- path: /
|
||||||
|
- name: api
|
||||||
|
source_dir: /
|
||||||
|
dockerfile_path: Dockerfile.api
|
||||||
|
github:
|
||||||
|
repo: your-username/scriptshare-cursor
|
||||||
|
branch: main
|
||||||
|
http_port: 3000
|
||||||
|
routes:
|
||||||
|
- path: /api
|
||||||
|
envs:
|
||||||
|
- key: NODE_ENV
|
||||||
|
value: production
|
||||||
|
- key: DATABASE_URL
|
||||||
|
value: ${DATABASE_URL}
|
||||||
|
databases:
|
||||||
|
- name: scriptshare-db
|
||||||
|
engine: MYSQL
|
||||||
|
version: "8"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Option 4: Railway
|
||||||
|
|
||||||
|
1. **Frontend**: Connect repo, Railway auto-detects Dockerfile
|
||||||
|
2. **API**: Deploy from same repo using `Dockerfile.api`
|
||||||
|
3. **Database**: Add MySQL service
|
||||||
|
4. Configure environment variables
|
||||||
|
|
||||||
|
### Option 5: Render
|
||||||
|
|
||||||
|
1. **Frontend**:
|
||||||
|
- Static Site
|
||||||
|
- Build Command: `npm run build`
|
||||||
|
- Publish Directory: `dist`
|
||||||
|
2. **API**:
|
||||||
|
- Web Service
|
||||||
|
- Docker build using `Dockerfile.api`
|
||||||
|
3. **Database**: Add MySQL database
|
||||||
|
|
||||||
|
## 🏗️ Build Commands
|
||||||
|
|
||||||
|
### Frontend
|
||||||
```bash
|
```bash
|
||||||
# Install doctl CLI
|
# Install dependencies
|
||||||
# On macOS: brew install doctl
|
npm install
|
||||||
# On Linux: snap install doctl
|
|
||||||
|
|
||||||
# Authenticate
|
# Build for production
|
||||||
doctl auth init
|
npm run build
|
||||||
|
|
||||||
# Create the app
|
# Preview build
|
||||||
doctl apps create --spec .do/app.yaml
|
npm run preview
|
||||||
```
|
```
|
||||||
|
|
||||||
## Step 3: Configure Environment Variables
|
### API
|
||||||
|
|
||||||
In the DigitalOcean dashboard, go to your app's Settings > Environment Variables and set:
|
|
||||||
|
|
||||||
### Required Variables
|
|
||||||
```
|
|
||||||
JWT_SECRET=your-super-secret-jwt-key-here-change-this-in-production
|
|
||||||
ADMIN_EMAIL=admin@yourcompany.com
|
|
||||||
ADMIN_USERNAME=admin
|
|
||||||
ADMIN_PASSWORD=your-secure-password
|
|
||||||
```
|
|
||||||
|
|
||||||
### Optional Variables
|
|
||||||
```
|
|
||||||
VITE_ANALYTICS_ENABLED=true
|
|
||||||
RATE_LIMIT_ENABLED=true
|
|
||||||
RATE_LIMIT_WINDOW_MS=900000
|
|
||||||
RATE_LIMIT_MAX_REQUESTS=100
|
|
||||||
```
|
|
||||||
|
|
||||||
⚠️ **Security Note**: Generate a strong JWT secret:
|
|
||||||
```bash
|
```bash
|
||||||
node -e "console.log(require('crypto').randomBytes(64).toString('hex'))"
|
# Install dependencies
|
||||||
|
npm install
|
||||||
|
|
||||||
|
# Build TypeScript
|
||||||
|
npm run build:api
|
||||||
|
|
||||||
|
# Start API server
|
||||||
|
npm run start:api
|
||||||
```
|
```
|
||||||
|
|
||||||
## Step 4: Database Setup
|
## 🔐 Environment Variables
|
||||||
|
|
||||||
The managed MySQL database will be automatically created. After the first deployment:
|
### Frontend (Build-time)
|
||||||
|
- `VITE_APP_NAME` - Application name
|
||||||
|
- `VITE_APP_URL` - Frontend URL
|
||||||
|
- `VITE_ANALYTICS_ENABLED` - Enable analytics (true/false)
|
||||||
|
|
||||||
1. **Run Database Migrations**:
|
### API (Runtime)
|
||||||
```bash
|
- `NODE_ENV` - Environment (production/development)
|
||||||
# In your app's console (or via GitHub Actions)
|
- `PORT` - Server port (default: 3000)
|
||||||
npm run db:setup:prod
|
- `DATABASE_URL` - MySQL connection string
|
||||||
```
|
- `JWT_SECRET` - JWT secret key
|
||||||
|
- `CORS_ORIGIN` - Allowed CORS origins
|
||||||
|
|
||||||
2. **Verify Database Connection**:
|
## 🗄️ Database Setup
|
||||||
Check the API health endpoint: `https://your-api-url/api/health`
|
|
||||||
|
|
||||||
## Step 5: Update App Configuration
|
### MySQL Connection String Format:
|
||||||
|
```
|
||||||
1. **Update Frontend URLs**: After deployment, update the environment variables with actual URLs:
|
DATABASE_URL=mysql://username:password@host:port/database
|
||||||
```
|
```
|
||||||
VITE_APP_URL=https://your-frontend-url.ondigitalocean.app
|
|
||||||
VITE_API_URL=https://your-api-url.ondigitalocean.app/api
|
|
||||||
CORS_ORIGIN=https://your-frontend-url.ondigitalocean.app
|
|
||||||
```
|
|
||||||
|
|
||||||
2. **Redeploy**: The app will automatically redeploy when you change environment variables.
|
|
||||||
|
|
||||||
## Step 6: Custom Domain (Optional)
|
|
||||||
|
|
||||||
1. In your app settings, go to **Domains**
|
|
||||||
2. Click **Add Domain**
|
|
||||||
3. Enter your domain name
|
|
||||||
4. Configure DNS records as instructed
|
|
||||||
|
|
||||||
## Database Management
|
|
||||||
|
|
||||||
### Connecting to the Database
|
|
||||||
|
|
||||||
|
### Required Tables:
|
||||||
|
The application uses Drizzle ORM. Run migrations after deployment:
|
||||||
```bash
|
```bash
|
||||||
# Get connection string from DigitalOcean dashboard
|
npm run db:migrate
|
||||||
mysql -h your-db-host -P 25060 -u your-username -p your-database-name --ssl-mode=REQUIRED
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Running Migrations
|
## 🔍 Health Checks
|
||||||
|
|
||||||
|
### Frontend Health Check:
|
||||||
|
```
|
||||||
|
GET /health
|
||||||
|
```
|
||||||
|
|
||||||
|
### API Health Check:
|
||||||
|
```
|
||||||
|
GET /api/health
|
||||||
|
```
|
||||||
|
|
||||||
|
## 📝 Platform-Specific Notes
|
||||||
|
|
||||||
|
### Vercel
|
||||||
|
- Frontend deploys automatically
|
||||||
|
- Use Vercel Functions for API (requires modification)
|
||||||
|
- Environment variables in Vercel dashboard
|
||||||
|
|
||||||
|
### Coolify
|
||||||
|
- Supports full Docker deployment
|
||||||
|
- Easy environment variable management
|
||||||
|
- Built-in SSL and domain management
|
||||||
|
|
||||||
|
### DigitalOcean App Platform
|
||||||
|
- Use `app.yaml` for configuration
|
||||||
|
- Automatic HTTPS
|
||||||
|
- Managed database available
|
||||||
|
|
||||||
|
### Railway
|
||||||
|
- Auto-deployment from Git
|
||||||
|
- Environment variables in dashboard
|
||||||
|
- Add-on database services
|
||||||
|
|
||||||
|
### Render
|
||||||
|
- Separate frontend (static) and backend (web service)
|
||||||
|
- Auto-deployment from Git
|
||||||
|
- Environment variables in dashboard
|
||||||
|
|
||||||
|
## 🐳 Docker Commands
|
||||||
|
|
||||||
|
### Build Frontend:
|
||||||
```bash
|
```bash
|
||||||
# Production migration
|
docker build -t scriptshare-frontend .
|
||||||
npm run db:migrate:prod
|
docker run -p 3000:80 scriptshare-frontend
|
||||||
|
|
||||||
# Create new migration
|
|
||||||
npm run db:generate
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Backup and Restore
|
### Build API:
|
||||||
|
|
||||||
DigitalOcean provides automatic daily backups. For manual backups:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Create backup
|
docker build -f Dockerfile.api -t scriptshare-api .
|
||||||
mysqldump -h your-db-host -P 25060 -u your-username -p your-database-name --ssl-mode=REQUIRED > backup.sql
|
docker run -p 3001:3000 scriptshare-api
|
||||||
|
|
||||||
# Restore backup
|
|
||||||
mysql -h your-db-host -P 25060 -u your-username -p your-database-name --ssl-mode=REQUIRED < backup.sql
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Monitoring and Logs
|
### Local Development:
|
||||||
|
```bash
|
||||||
|
docker-compose up
|
||||||
|
```
|
||||||
|
|
||||||
### Application Logs
|
## 🔧 Local Development
|
||||||
- View logs in DigitalOcean Console: App → Runtime Logs
|
|
||||||
- Or via CLI: `doctl apps logs <app-id> --type=run`
|
|
||||||
|
|
||||||
### Database Monitoring
|
### Frontend:
|
||||||
- Database metrics available in DigitalOcean dashboard
|
```bash
|
||||||
- Set up alerts for CPU, memory, and connection usage
|
npm run dev
|
||||||
|
```
|
||||||
|
|
||||||
### Health Checks
|
### API:
|
||||||
- API: `https://your-api-url/api/health`
|
```bash
|
||||||
- Frontend: Built-in App Platform health checks
|
npm run build:api
|
||||||
|
npm run start:api
|
||||||
|
```
|
||||||
|
|
||||||
## Scaling
|
### Database:
|
||||||
|
```bash
|
||||||
|
npm run db:studio # Drizzle Studio
|
||||||
|
npm run db:migrate # Run migrations
|
||||||
|
```
|
||||||
|
|
||||||
### Vertical Scaling
|
## 🚀 Quick Deploy Examples
|
||||||
- Increase instance size in App Platform settings
|
|
||||||
- Database can be scaled up (not down) in database settings
|
|
||||||
|
|
||||||
### Horizontal Scaling
|
### Deploy to Vercel (Frontend):
|
||||||
- Increase instance count for API service
|
```bash
|
||||||
- Frontend is automatically scaled as a static site
|
vercel --prod
|
||||||
|
```
|
||||||
|
|
||||||
## Security Best Practices
|
### Deploy to Railway:
|
||||||
|
```bash
|
||||||
|
railway deploy
|
||||||
|
```
|
||||||
|
|
||||||
1. **Environment Variables**: Never commit secrets to Git
|
### Deploy to Render:
|
||||||
2. **Database Access**: Use DigitalOcean's private networking
|
Connect GitHub repository in Render dashboard
|
||||||
3. **SSL/TLS**: Enabled by default on App Platform
|
|
||||||
4. **Database Backups**: Verify daily backups are working
|
|
||||||
5. **Access Control**: Use DigitalOcean teams for access management
|
|
||||||
|
|
||||||
## Troubleshooting
|
## 📞 Support
|
||||||
|
|
||||||
### Common Issues
|
- **Documentation**: Check platform-specific documentation
|
||||||
|
- **Environment**: Ensure all required environment variables are set
|
||||||
|
- **Health Checks**: Monitor `/health` and `/api/health` endpoints
|
||||||
|
- **Logs**: Check platform logs for deployment issues
|
||||||
|
|
||||||
1. **Build Failures**:
|
---
|
||||||
```bash
|
|
||||||
# Check build logs
|
|
||||||
doctl apps logs <app-id> --type=build
|
|
||||||
```
|
|
||||||
|
|
||||||
2. **Database Connection Issues**:
|
**Your ScriptShare application is ready for deployment on any modern platform! 🎉**
|
||||||
- Verify DATABASE_URL format
|
|
||||||
- Check firewall settings
|
|
||||||
- Ensure SSL is enabled
|
|
||||||
|
|
||||||
3. **CORS Errors**:
|
Choose the platform that best fits your needs - from simple static hosting to full-stack container deployments.
|
||||||
- Verify CORS_ORIGIN matches frontend URL
|
|
||||||
- Check environment variable casing
|
|
||||||
|
|
||||||
4. **Missing Dependencies**:
|
|
||||||
```bash
|
|
||||||
# Clear npm cache and rebuild
|
|
||||||
npm ci --clean-cache
|
|
||||||
```
|
|
||||||
|
|
||||||
### Getting Support
|
|
||||||
|
|
||||||
- DigitalOcean Community: https://www.digitalocean.com/community
|
|
||||||
- Support tickets: https://cloud.digitalocean.com/support
|
|
||||||
- Documentation: https://docs.digitalocean.com/products/app-platform/
|
|
||||||
|
|
||||||
## Cost Optimization
|
|
||||||
|
|
||||||
### Current Configuration Costs (Approximate)
|
|
||||||
- **API Service**: $5/month (Basic plan)
|
|
||||||
- **Database**: $15/month (1GB RAM, 1 vCPU)
|
|
||||||
- **Static Site**: $0 (included with API service)
|
|
||||||
- **Total**: ~$20/month
|
|
||||||
|
|
||||||
### Cost Reduction Tips
|
|
||||||
1. Use development database for testing
|
|
||||||
2. Scale down during low usage periods
|
|
||||||
3. Monitor and optimize database queries
|
|
||||||
4. Use CDN for static assets
|
|
||||||
|
|
||||||
## Deployment Checklist
|
|
||||||
|
|
||||||
- [ ] Repository configured with deployment files
|
|
||||||
- [ ] Environment variables set in DigitalOcean
|
|
||||||
- [ ] JWT secret generated and configured
|
|
||||||
- [ ] Database migrations run successfully
|
|
||||||
- [ ] Health check endpoints responding
|
|
||||||
- [ ] Frontend can communicate with API
|
|
||||||
- [ ] Admin user created and accessible
|
|
||||||
- [ ] Custom domain configured (if applicable)
|
|
||||||
- [ ] Monitoring and alerts set up
|
|
||||||
- [ ] Backup strategy verified
|
|
||||||
|
|
||||||
## Next Steps
|
|
||||||
|
|
||||||
1. **Set up CI/CD**: Configure GitHub Actions for automated deployments
|
|
||||||
2. **Monitoring**: Set up application performance monitoring
|
|
||||||
3. **CDN**: Configure CDN for static assets
|
|
||||||
4. **Analytics**: Integrate application analytics
|
|
||||||
5. **Error Tracking**: Set up error monitoring service
|
|
||||||
|
|
||||||
## Support
|
|
||||||
|
|
||||||
For issues specific to this deployment setup, please check:
|
|
||||||
1. DigitalOcean App Platform documentation
|
|
||||||
2. Application logs in the DigitalOcean console
|
|
||||||
3. Database connection and query logs
|
|
||||||
|
|
||||||
Remember to regularly update dependencies and monitor security advisories for your application stack.
|
|
@ -1,365 +0,0 @@
|
|||||||
# 🐳 ScriptShare Docker Deployment Guide
|
|
||||||
|
|
||||||
## Overview
|
|
||||||
|
|
||||||
This guide covers deploying ScriptShare to any generic Docker server using Docker Compose. The setup includes:
|
|
||||||
|
|
||||||
- **Frontend**: React application served by Nginx
|
|
||||||
- **Backend API**: Node.js Express server
|
|
||||||
- **Database**: MySQL 8.0
|
|
||||||
- **Reverse Proxy**: Nginx with load balancing
|
|
||||||
- **Cache**: Redis (optional)
|
|
||||||
- **Monitoring**: Health checks and logging
|
|
||||||
|
|
||||||
## Prerequisites
|
|
||||||
|
|
||||||
- Docker Engine 20.10+
|
|
||||||
- Docker Compose 2.0+
|
|
||||||
- At least 2GB RAM
|
|
||||||
- 10GB+ disk space
|
|
||||||
- Linux/macOS server (Windows with WSL2)
|
|
||||||
|
|
||||||
## Quick Start
|
|
||||||
|
|
||||||
### 1. **Prepare Environment**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Clone the repository
|
|
||||||
git clone <your-repo-url>
|
|
||||||
cd scriptshare-cursor
|
|
||||||
|
|
||||||
# Copy and configure environment
|
|
||||||
cp env.production .env
|
|
||||||
# Edit .env with your specific settings
|
|
||||||
nano .env
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. **Deploy Application**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Make scripts executable (Linux/macOS)
|
|
||||||
chmod +x scripts/*.sh
|
|
||||||
|
|
||||||
# Run deployment
|
|
||||||
./scripts/deploy.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
### 3. **Verify Deployment**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Check service status
|
|
||||||
./scripts/manage.sh status
|
|
||||||
|
|
||||||
# View logs
|
|
||||||
./scripts/manage.sh logs
|
|
||||||
```
|
|
||||||
|
|
||||||
## Configuration
|
|
||||||
|
|
||||||
### Environment Variables
|
|
||||||
|
|
||||||
Edit `env.production` before deployment:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Domain Configuration
|
|
||||||
APP_URL=https://your-domain.com
|
|
||||||
FRONTEND_URL=https://your-domain.com
|
|
||||||
CORS_ORIGIN=https://your-domain.com
|
|
||||||
|
|
||||||
# Security (CHANGE THESE!)
|
|
||||||
JWT_SECRET=your-super-secret-jwt-key
|
|
||||||
DB_PASSWORD=your-secure-database-password
|
|
||||||
DB_ROOT_PASSWORD=your-root-password
|
|
||||||
REDIS_PASSWORD=your-redis-password
|
|
||||||
|
|
||||||
# Ports (adjust if needed)
|
|
||||||
PROXY_PORT=80
|
|
||||||
PROXY_SSL_PORT=443
|
|
||||||
API_PORT=3001
|
|
||||||
```
|
|
||||||
|
|
||||||
### SSL Configuration
|
|
||||||
|
|
||||||
1. **Place SSL certificates** in `./certs/`:
|
|
||||||
```
|
|
||||||
certs/
|
|
||||||
├── fullchain.pem
|
|
||||||
└── privkey.pem
|
|
||||||
```
|
|
||||||
|
|
||||||
2. **Enable HTTPS** in `nginx/conf.d/scriptshare.conf`:
|
|
||||||
- Uncomment the SSL server block
|
|
||||||
- Update `server_name` with your domain
|
|
||||||
|
|
||||||
3. **Restart proxy**:
|
|
||||||
```bash
|
|
||||||
./scripts/manage.sh restart scriptshare-proxy
|
|
||||||
```
|
|
||||||
|
|
||||||
## Service Architecture
|
|
||||||
|
|
||||||
```
|
|
||||||
┌─────────────────┐ ┌─────────────────┐
|
|
||||||
│ Nginx Proxy │────│ Frontend │
|
|
||||||
│ Port 80/443 │ │ (React+Nginx) │
|
|
||||||
└─────────────────┘ └─────────────────┘
|
|
||||||
│ │
|
|
||||||
│ ┌─────────────────┐
|
|
||||||
└──────────────│ Backend API │
|
|
||||||
│ (Node.js) │
|
|
||||||
└─────────────────┘
|
|
||||||
│
|
|
||||||
┌─────────────────┐
|
|
||||||
│ MySQL 8.0 │
|
|
||||||
│ Database │
|
|
||||||
└─────────────────┘
|
|
||||||
│
|
|
||||||
┌─────────────────┐
|
|
||||||
│ Redis Cache │
|
|
||||||
│ (Optional) │
|
|
||||||
└─────────────────┘
|
|
||||||
```
|
|
||||||
|
|
||||||
## Management Commands
|
|
||||||
|
|
||||||
### Service Management
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Start all services
|
|
||||||
./scripts/manage.sh start
|
|
||||||
|
|
||||||
# Stop all services
|
|
||||||
./scripts/manage.sh stop
|
|
||||||
|
|
||||||
# Restart services
|
|
||||||
./scripts/manage.sh restart
|
|
||||||
|
|
||||||
# View service status
|
|
||||||
./scripts/manage.sh status
|
|
||||||
|
|
||||||
# View logs (all services)
|
|
||||||
./scripts/manage.sh logs
|
|
||||||
|
|
||||||
# View logs (specific service)
|
|
||||||
./scripts/manage.sh logs scriptshare-api
|
|
||||||
```
|
|
||||||
|
|
||||||
### Database Management
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Connect to database
|
|
||||||
./scripts/manage.sh db
|
|
||||||
|
|
||||||
# Create backup
|
|
||||||
./scripts/manage.sh backup
|
|
||||||
|
|
||||||
# Run migrations (from API container)
|
|
||||||
docker-compose -f docker-compose.prod.yml exec scriptshare-api npm run db:migrate:prod
|
|
||||||
```
|
|
||||||
|
|
||||||
### Maintenance
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Update application
|
|
||||||
./scripts/manage.sh update
|
|
||||||
|
|
||||||
# Clean up Docker resources
|
|
||||||
./scripts/manage.sh clean
|
|
||||||
|
|
||||||
# Open shell in container
|
|
||||||
./scripts/manage.sh shell scriptshare-api
|
|
||||||
```
|
|
||||||
|
|
||||||
## Port Configuration
|
|
||||||
|
|
||||||
| Service | Internal Port | External Port | Description |
|
|
||||||
|---------|---------------|---------------|-------------|
|
|
||||||
| Proxy | 80, 443 | 8080, 8443 | Main entry point |
|
|
||||||
| Frontend | 80 | - | React application |
|
|
||||||
| API | 3000 | 3001 | REST API |
|
|
||||||
| Database | 3306 | 3306 | MySQL database |
|
|
||||||
| Redis | 6379 | 6379 | Cache store |
|
|
||||||
|
|
||||||
## Monitoring
|
|
||||||
|
|
||||||
### Health Checks
|
|
||||||
|
|
||||||
All services include health checks:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Check health status
|
|
||||||
curl http://localhost:8080/health
|
|
||||||
|
|
||||||
# API health
|
|
||||||
curl http://localhost:3001/api/health
|
|
||||||
|
|
||||||
# Individual service health
|
|
||||||
docker ps --format "table {{.Names}}\t{{.Status}}"
|
|
||||||
```
|
|
||||||
|
|
||||||
### Logging
|
|
||||||
|
|
||||||
Logs are stored in Docker volumes and can be accessed via:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# All services
|
|
||||||
docker-compose -f docker-compose.prod.yml logs -f
|
|
||||||
|
|
||||||
# Specific service
|
|
||||||
docker-compose -f docker-compose.prod.yml logs -f scriptshare-api
|
|
||||||
|
|
||||||
# Save logs to file
|
|
||||||
docker-compose -f docker-compose.prod.yml logs > scriptshare.log
|
|
||||||
```
|
|
||||||
|
|
||||||
## Backup & Recovery
|
|
||||||
|
|
||||||
### Automated Backups
|
|
||||||
|
|
||||||
Configure automated backups by adding to crontab:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Edit crontab
|
|
||||||
crontab -e
|
|
||||||
|
|
||||||
# Add daily backup at 2 AM
|
|
||||||
0 2 * * * /path/to/scriptshare/scripts/backup.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
### Manual Backup
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Create backup
|
|
||||||
./scripts/backup.sh
|
|
||||||
|
|
||||||
# Backups are stored in ./backups/
|
|
||||||
ls -la backups/
|
|
||||||
```
|
|
||||||
|
|
||||||
### Recovery
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Stop database
|
|
||||||
docker-compose -f docker-compose.prod.yml stop scriptshare-db
|
|
||||||
|
|
||||||
# Restore from backup
|
|
||||||
gunzip -c backups/scriptshare_backup_YYYYMMDD_HHMMSS.sql.gz | \
|
|
||||||
docker exec -i scriptshare-db mysql -u root -p'your-root-password'
|
|
||||||
|
|
||||||
# Start database
|
|
||||||
docker-compose -f docker-compose.prod.yml start scriptshare-db
|
|
||||||
```
|
|
||||||
|
|
||||||
## Security Considerations
|
|
||||||
|
|
||||||
### 1. **Change Default Passwords**
|
|
||||||
- Update all passwords in `env.production`
|
|
||||||
- Use strong, unique passwords
|
|
||||||
- Consider using environment variable files
|
|
||||||
|
|
||||||
### 2. **Network Security**
|
|
||||||
- Configure firewall rules
|
|
||||||
- Use reverse proxy for SSL termination
|
|
||||||
- Implement rate limiting (configured in nginx)
|
|
||||||
|
|
||||||
### 3. **SSL/TLS**
|
|
||||||
- Use Let's Encrypt for free SSL certificates
|
|
||||||
- Configure HSTS headers
|
|
||||||
- Use modern TLS protocols only
|
|
||||||
|
|
||||||
### 4. **Container Security**
|
|
||||||
- Keep Docker images updated
|
|
||||||
- Run containers with non-root users where possible
|
|
||||||
- Use Docker secrets for sensitive data
|
|
||||||
|
|
||||||
## Troubleshooting
|
|
||||||
|
|
||||||
### Common Issues
|
|
||||||
|
|
||||||
1. **Services won't start**:
|
|
||||||
```bash
|
|
||||||
# Check logs
|
|
||||||
docker-compose -f docker-compose.prod.yml logs
|
|
||||||
|
|
||||||
# Check disk space
|
|
||||||
df -h
|
|
||||||
|
|
||||||
# Check memory
|
|
||||||
free -h
|
|
||||||
```
|
|
||||||
|
|
||||||
2. **Database connection errors**:
|
|
||||||
```bash
|
|
||||||
# Test database connectivity
|
|
||||||
docker exec scriptshare-db mysqladmin ping -u root -p'password'
|
|
||||||
|
|
||||||
# Check database logs
|
|
||||||
docker-compose -f docker-compose.prod.yml logs scriptshare-db
|
|
||||||
```
|
|
||||||
|
|
||||||
3. **API not responding**:
|
|
||||||
```bash
|
|
||||||
# Check API health
|
|
||||||
curl http://localhost:3001/api/health
|
|
||||||
|
|
||||||
# Check API logs
|
|
||||||
docker-compose -f docker-compose.prod.yml logs scriptshare-api
|
|
||||||
```
|
|
||||||
|
|
||||||
### Performance Tuning
|
|
||||||
|
|
||||||
1. **Database Optimization**:
|
|
||||||
- Adjust `innodb_buffer_pool_size` in MySQL configuration
|
|
||||||
- Monitor slow query log
|
|
||||||
- Add database indexes as needed
|
|
||||||
|
|
||||||
2. **Nginx Optimization**:
|
|
||||||
- Enable gzip compression (configured)
|
|
||||||
- Adjust worker processes
|
|
||||||
- Configure caching headers
|
|
||||||
|
|
||||||
3. **Resource Limits**:
|
|
||||||
- Set memory and CPU limits in docker-compose.prod.yml
|
|
||||||
- Monitor resource usage with `docker stats`
|
|
||||||
|
|
||||||
## Scaling
|
|
||||||
|
|
||||||
### Horizontal Scaling
|
|
||||||
|
|
||||||
To scale the application:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Scale API containers
|
|
||||||
docker-compose -f docker-compose.prod.yml up -d --scale scriptshare-api=3
|
|
||||||
|
|
||||||
# Scale frontend containers
|
|
||||||
docker-compose -f docker-compose.prod.yml up -d --scale scriptshare-frontend=2
|
|
||||||
```
|
|
||||||
|
|
||||||
### Load Balancing
|
|
||||||
|
|
||||||
Nginx automatically load balances between multiple container instances.
|
|
||||||
|
|
||||||
## Production Checklist
|
|
||||||
|
|
||||||
- [ ] Update all default passwords
|
|
||||||
- [ ] Configure SSL certificates
|
|
||||||
- [ ] Set up automated backups
|
|
||||||
- [ ] Configure monitoring and alerting
|
|
||||||
- [ ] Set up log rotation
|
|
||||||
- [ ] Configure firewall rules
|
|
||||||
- [ ] Test disaster recovery procedures
|
|
||||||
- [ ] Set up domain and DNS
|
|
||||||
- [ ] Configure SMTP for emails (if applicable)
|
|
||||||
- [ ] Set up monitoring dashboard
|
|
||||||
|
|
||||||
## Support
|
|
||||||
|
|
||||||
For issues and questions:
|
|
||||||
|
|
||||||
1. Check the logs first
|
|
||||||
2. Review this documentation
|
|
||||||
3. Check Docker and system resources
|
|
||||||
4. Create an issue in the repository
|
|
||||||
|
|
||||||
**Your ScriptShare application is now ready for production deployment! 🚀**
|
|
207
Dockerfile.api
207
Dockerfile.api
@ -1,8 +1,8 @@
|
|||||||
# Production API Dockerfile for DigitalOcean
|
# ScriptShare API Dockerfile
|
||||||
FROM node:18-alpine
|
FROM node:18-alpine
|
||||||
|
|
||||||
# Install system dependencies for native modules
|
# Install system dependencies for native modules
|
||||||
RUN apk add --no-cache python3 make g++ libc6-compat
|
RUN apk add --no-cache python3 make g++ libc6-compat curl
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
@ -10,208 +10,13 @@ WORKDIR /app
|
|||||||
COPY package*.json ./
|
COPY package*.json ./
|
||||||
|
|
||||||
# Install dependencies
|
# Install dependencies
|
||||||
RUN npm ci --only=production=false --silent
|
RUN npm ci --only=production=false
|
||||||
|
|
||||||
# Copy source code
|
# Copy source code
|
||||||
COPY . .
|
COPY . .
|
||||||
|
|
||||||
# Create API-only build by removing frontend dependencies and files
|
# Build TypeScript
|
||||||
RUN npm uninstall @vitejs/plugin-react-swc vite
|
RUN npx tsc --build
|
||||||
RUN rm -rf src/components src/pages src/contexts src/hooks/use-toast.ts src/utils/toast.ts
|
|
||||||
RUN rm -rf src/main.tsx src/App.tsx src/index.css
|
|
||||||
RUN rm -rf public index.html vite.config.ts tailwind.config.ts postcss.config.js
|
|
||||||
|
|
||||||
# Keep only API and database files
|
|
||||||
# The structure will be: src/lib/api/* and src/lib/db/*
|
|
||||||
|
|
||||||
# Create a simple Express server
|
|
||||||
RUN cat > src/server.ts << 'EOF'
|
|
||||||
import express from 'express';
|
|
||||||
import cors from 'cors';
|
|
||||||
import { createUser, getUserByEmail, updateUser, getAllUsers, getUserById } from './lib/api/users.js';
|
|
||||||
import { getScripts, getScriptById, createScript, updateScript, deleteScript, moderateScript } from './lib/api/scripts.js';
|
|
||||||
import { login, register, refreshToken } from './lib/api/auth.js';
|
|
||||||
import { rateScript, getUserRating, getScriptRatingStats } from './lib/api/ratings.js';
|
|
||||||
import { getPlatformAnalytics, getScriptAnalytics, trackEvent } from './lib/api/analytics.js';
|
|
||||||
import { createCollection, getUserCollections, getPublicCollections, addScriptToCollection } from './lib/api/collections.js';
|
|
||||||
|
|
||||||
const app = express();
|
|
||||||
const PORT = process.env.PORT || 3000;
|
|
||||||
|
|
||||||
// Middleware
|
|
||||||
app.use(cors({
|
|
||||||
origin: process.env.CORS_ORIGIN || '*',
|
|
||||||
credentials: true
|
|
||||||
}));
|
|
||||||
app.use(express.json({ limit: '10mb' }));
|
|
||||||
app.use(express.urlencoded({ extended: true }));
|
|
||||||
|
|
||||||
// Health check endpoint
|
|
||||||
app.get('/api/health', (req, res) => {
|
|
||||||
res.json({ status: 'ok', timestamp: new Date().toISOString() });
|
|
||||||
});
|
|
||||||
|
|
||||||
// Auth routes
|
|
||||||
app.post('/api/auth/login', async (req, res) => {
|
|
||||||
try {
|
|
||||||
const result = await login(req.body);
|
|
||||||
res.json(result);
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Login error:', error);
|
|
||||||
res.status(401).json({ error: 'Invalid credentials' });
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
app.post('/api/auth/register', async (req, res) => {
|
|
||||||
try {
|
|
||||||
const result = await register(req.body);
|
|
||||||
res.json(result);
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Register error:', error);
|
|
||||||
res.status(400).json({ error: 'Registration failed' });
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Scripts routes
|
|
||||||
app.get('/api/scripts', async (req, res) => {
|
|
||||||
try {
|
|
||||||
const result = await getScripts(req.query);
|
|
||||||
res.json(result);
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Get scripts error:', error);
|
|
||||||
res.status(500).json({ error: 'Failed to fetch scripts' });
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
app.get('/api/scripts/:id', async (req, res) => {
|
|
||||||
try {
|
|
||||||
const script = await getScriptById(req.params.id);
|
|
||||||
if (!script) {
|
|
||||||
return res.status(404).json({ error: 'Script not found' });
|
|
||||||
}
|
|
||||||
res.json(script);
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Get script error:', error);
|
|
||||||
res.status(500).json({ error: 'Failed to fetch script' });
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
app.post('/api/scripts', async (req, res) => {
|
|
||||||
try {
|
|
||||||
const userId = req.headers['x-user-id'] as string;
|
|
||||||
if (!userId) {
|
|
||||||
return res.status(401).json({ error: 'Unauthorized' });
|
|
||||||
}
|
|
||||||
const result = await createScript(req.body, userId);
|
|
||||||
res.json(result);
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Create script error:', error);
|
|
||||||
res.status(500).json({ error: 'Failed to create script' });
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Users routes
|
|
||||||
app.get('/api/users', async (req, res) => {
|
|
||||||
try {
|
|
||||||
const result = await getAllUsers();
|
|
||||||
res.json(result);
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Get users error:', error);
|
|
||||||
res.status(500).json({ error: 'Failed to fetch users' });
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
app.get('/api/users/:id', async (req, res) => {
|
|
||||||
try {
|
|
||||||
const user = await getUserById(req.params.id);
|
|
||||||
if (!user) {
|
|
||||||
return res.status(404).json({ error: 'User not found' });
|
|
||||||
}
|
|
||||||
res.json(user);
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Get user error:', error);
|
|
||||||
res.status(500).json({ error: 'Failed to fetch user' });
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Analytics routes
|
|
||||||
app.get('/api/analytics/platform', async (req, res) => {
|
|
||||||
try {
|
|
||||||
const days = parseInt(req.query.days as string) || 30;
|
|
||||||
const result = await getPlatformAnalytics(days);
|
|
||||||
res.json(result);
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Analytics error:', error);
|
|
||||||
res.status(500).json({ error: 'Failed to fetch analytics' });
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
app.post('/api/analytics/track', async (req, res) => {
|
|
||||||
try {
|
|
||||||
const result = await trackEvent(req.body);
|
|
||||||
res.json(result);
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Track event error:', error);
|
|
||||||
res.status(500).json({ error: 'Failed to track event' });
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Collections routes
|
|
||||||
app.get('/api/collections', async (req, res) => {
|
|
||||||
try {
|
|
||||||
const userId = req.headers['x-user-id'] as string;
|
|
||||||
const result = userId ? await getUserCollections(userId) : await getPublicCollections();
|
|
||||||
res.json(result);
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Get collections error:', error);
|
|
||||||
res.status(500).json({ error: 'Failed to fetch collections' });
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Ratings routes
|
|
||||||
app.post('/api/ratings', async (req, res) => {
|
|
||||||
try {
|
|
||||||
const result = await rateScript(req.body);
|
|
||||||
res.json(result);
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Rate script error:', error);
|
|
||||||
res.status(500).json({ error: 'Failed to rate script' });
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
app.get('/api/scripts/:id/ratings', async (req, res) => {
|
|
||||||
try {
|
|
||||||
const result = await getScriptRatingStats(req.params.id);
|
|
||||||
res.json(result);
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Get ratings error:', error);
|
|
||||||
res.status(500).json({ error: 'Failed to fetch ratings' });
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Error handling middleware
|
|
||||||
app.use((error: any, req: express.Request, res: express.Response, next: express.NextFunction) => {
|
|
||||||
console.error('Unhandled error:', error);
|
|
||||||
res.status(500).json({ error: 'Internal server error' });
|
|
||||||
});
|
|
||||||
|
|
||||||
// 404 handler
|
|
||||||
app.use('*', (req, res) => {
|
|
||||||
res.status(404).json({ error: 'Endpoint not found' });
|
|
||||||
});
|
|
||||||
|
|
||||||
app.listen(PORT, () => {
|
|
||||||
console.log(`ScriptShare API server running on port ${PORT}`);
|
|
||||||
console.log(`Environment: ${process.env.NODE_ENV}`);
|
|
||||||
console.log(`Database URL configured: ${!!process.env.DATABASE_URL}`);
|
|
||||||
});
|
|
||||||
EOF
|
|
||||||
|
|
||||||
# Install Express and CORS for the API server
|
|
||||||
RUN npm install express cors @types/express @types/cors
|
|
||||||
|
|
||||||
# Build TypeScript (if any TS files remain)
|
|
||||||
RUN npx tsc --build || echo "TypeScript build completed with warnings"
|
|
||||||
|
|
||||||
# Expose port
|
# Expose port
|
||||||
EXPOSE 3000
|
EXPOSE 3000
|
||||||
@ -221,4 +26,4 @@ HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \
|
|||||||
CMD curl -f http://localhost:3000/api/health || exit 1
|
CMD curl -f http://localhost:3000/api/health || exit 1
|
||||||
|
|
||||||
# Start the API server
|
# Start the API server
|
||||||
CMD ["node", "src/server.js"]
|
CMD ["npm", "run", "start:api"]
|
@ -1,180 +0,0 @@
|
|||||||
# 🚀 ScriptShare - Generic Docker Server Deployment
|
|
||||||
|
|
||||||
## 🎯 Deployment Summary
|
|
||||||
|
|
||||||
Your ScriptShare application has been successfully reconfigured for deployment on any generic Docker server! The setup provides a complete, production-ready environment with all necessary components.
|
|
||||||
|
|
||||||
## 📦 What's Included
|
|
||||||
|
|
||||||
### **🐳 Docker Infrastructure**
|
|
||||||
- **Production Docker Compose**: Complete multi-service stack
|
|
||||||
- **Frontend Container**: React app with Nginx
|
|
||||||
- **Backend API Container**: Node.js Express server
|
|
||||||
- **Database Container**: MySQL 8.0 with optimizations
|
|
||||||
- **Reverse Proxy**: Nginx with load balancing & SSL support
|
|
||||||
- **Cache Layer**: Redis for session/data caching
|
|
||||||
- **Health Monitoring**: All services include health checks
|
|
||||||
|
|
||||||
### **⚙️ Configuration Files**
|
|
||||||
- `docker-compose.prod.yml` - Production environment setup
|
|
||||||
- `env.production` - Environment variables template
|
|
||||||
- `nginx/nginx.conf` - Main Nginx configuration
|
|
||||||
- `nginx/conf.d/scriptshare.conf` - Application-specific routing
|
|
||||||
|
|
||||||
### **🛠️ Management Tools**
|
|
||||||
- `scripts/deploy.sh` - Automated deployment script
|
|
||||||
- `scripts/manage.sh` - Service management (Linux/macOS)
|
|
||||||
- `scripts/manage.ps1` - Service management (Windows)
|
|
||||||
- `scripts/backup.sh` - Database backup automation
|
|
||||||
|
|
||||||
### **📚 Documentation**
|
|
||||||
- `DOCKER_DEPLOYMENT.md` - Comprehensive deployment guide
|
|
||||||
- Complete configuration examples
|
|
||||||
- Troubleshooting and maintenance guides
|
|
||||||
|
|
||||||
## 🚀 Quick Deployment
|
|
||||||
|
|
||||||
### **Prerequisites**
|
|
||||||
- Docker Engine 20.10+
|
|
||||||
- Docker Compose 2.0+
|
|
||||||
- 2GB+ RAM, 10GB+ disk space
|
|
||||||
|
|
||||||
### **Deploy in 3 Steps**
|
|
||||||
|
|
||||||
1. **Configure Environment**:
|
|
||||||
```bash
|
|
||||||
cp env.production .env
|
|
||||||
# Edit .env with your domain and passwords
|
|
||||||
```
|
|
||||||
|
|
||||||
2. **Deploy Application**:
|
|
||||||
```bash
|
|
||||||
# Linux/macOS
|
|
||||||
chmod +x scripts/*.sh
|
|
||||||
./scripts/deploy.sh
|
|
||||||
|
|
||||||
# Windows PowerShell
|
|
||||||
.\scripts\manage.ps1 start
|
|
||||||
```
|
|
||||||
|
|
||||||
3. **Verify Deployment**:
|
|
||||||
```bash
|
|
||||||
# Check status
|
|
||||||
./scripts/manage.sh status
|
|
||||||
|
|
||||||
# View application
|
|
||||||
http://localhost:8080
|
|
||||||
```
|
|
||||||
|
|
||||||
## 🌐 Service Architecture
|
|
||||||
|
|
||||||
```
|
|
||||||
Internet
|
|
||||||
↓
|
|
||||||
┌─────────────────┐ Port 80/443
|
|
||||||
│ Nginx Proxy │ (Load Balancer)
|
|
||||||
└─────────────────┘
|
|
||||||
↓ ↓
|
|
||||||
┌─────────┐ ┌─────────────────┐
|
|
||||||
│Frontend │ │ Backend API │
|
|
||||||
│(React) │ │ (Node.js) │
|
|
||||||
└─────────┘ └─────────────────┘
|
|
||||||
↓
|
|
||||||
┌─────────────────┐
|
|
||||||
│ MySQL 8.0 │
|
|
||||||
│ Database │
|
|
||||||
└─────────────────┘
|
|
||||||
↓
|
|
||||||
┌─────────────────┐
|
|
||||||
│ Redis Cache │
|
|
||||||
│ (Optional) │
|
|
||||||
└─────────────────┘
|
|
||||||
```
|
|
||||||
|
|
||||||
## 🔧 Key Features
|
|
||||||
|
|
||||||
### **Production Ready**
|
|
||||||
- ✅ Multi-container architecture
|
|
||||||
- ✅ Health checks and monitoring
|
|
||||||
- ✅ Automated backup system
|
|
||||||
- ✅ SSL/HTTPS support
|
|
||||||
- ✅ Rate limiting and security headers
|
|
||||||
- ✅ Database optimizations
|
|
||||||
- ✅ Log management
|
|
||||||
- ✅ Resource management
|
|
||||||
|
|
||||||
### **Easy Management**
|
|
||||||
- ✅ One-command deployment
|
|
||||||
- ✅ Service start/stop/restart
|
|
||||||
- ✅ Real-time log viewing
|
|
||||||
- ✅ Database backup/restore
|
|
||||||
- ✅ Application updates
|
|
||||||
- ✅ Resource cleanup
|
|
||||||
- ✅ Health monitoring
|
|
||||||
|
|
||||||
### **Scalable**
|
|
||||||
- ✅ Horizontal scaling support
|
|
||||||
- ✅ Load balancing configured
|
|
||||||
- ✅ Container orchestration
|
|
||||||
- ✅ Resource limits
|
|
||||||
- ✅ Performance monitoring
|
|
||||||
|
|
||||||
## 📋 Post-Deployment Checklist
|
|
||||||
|
|
||||||
1. **Security Configuration**:
|
|
||||||
- [ ] Update all default passwords in `.env`
|
|
||||||
- [ ] Configure SSL certificates
|
|
||||||
- [ ] Set up firewall rules
|
|
||||||
- [ ] Review security headers
|
|
||||||
|
|
||||||
2. **Domain Setup**:
|
|
||||||
- [ ] Point your domain to the server
|
|
||||||
- [ ] Update `APP_URL` in environment
|
|
||||||
- [ ] Configure SSL certificates
|
|
||||||
- [ ] Test HTTPS redirect
|
|
||||||
|
|
||||||
3. **Monitoring & Maintenance**:
|
|
||||||
- [ ] Set up automated backups (cron)
|
|
||||||
- [ ] Configure log rotation
|
|
||||||
- [ ] Test disaster recovery
|
|
||||||
- [ ] Set up monitoring alerts
|
|
||||||
|
|
||||||
4. **Application Setup**:
|
|
||||||
- [ ] Run database migrations
|
|
||||||
- [ ] Create admin user
|
|
||||||
- [ ] Test all functionality
|
|
||||||
- [ ] Configure SMTP (if needed)
|
|
||||||
|
|
||||||
## 🆘 Quick Commands
|
|
||||||
|
|
||||||
### **Service Management**
|
|
||||||
```bash
|
|
||||||
./scripts/manage.sh start # Start all services
|
|
||||||
./scripts/manage.sh stop # Stop all services
|
|
||||||
./scripts/manage.sh status # Check service status
|
|
||||||
./scripts/manage.sh logs # View logs
|
|
||||||
```
|
|
||||||
|
|
||||||
### **Database Operations**
|
|
||||||
```bash
|
|
||||||
./scripts/manage.sh backup # Create database backup
|
|
||||||
./scripts/manage.sh db # Connect to database
|
|
||||||
```
|
|
||||||
|
|
||||||
### **Maintenance**
|
|
||||||
```bash
|
|
||||||
./scripts/manage.sh update # Update application
|
|
||||||
./scripts/manage.sh clean # Clean Docker resources
|
|
||||||
```
|
|
||||||
|
|
||||||
## 📞 Support
|
|
||||||
|
|
||||||
- **Documentation**: See `DOCKER_DEPLOYMENT.md` for detailed instructions
|
|
||||||
- **Troubleshooting**: Check logs with `./scripts/manage.sh logs`
|
|
||||||
- **Updates**: Use `./scripts/manage.sh update` for application updates
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**🎉 Your ScriptShare application is now ready for production deployment on any Docker server!**
|
|
||||||
|
|
||||||
The setup provides enterprise-grade reliability, security, and scalability while maintaining simplicity for day-to-day operations. All components are containerized, monitored, and ready for production workloads.
|
|
128
REVERT_SUMMARY.md
Normal file
128
REVERT_SUMMARY.md
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
# ✅ ScriptShare - Reverted to Standard Docker Deployment
|
||||||
|
|
||||||
|
## 🔄 Reversion Complete
|
||||||
|
|
||||||
|
Your ScriptShare application has been successfully reverted from the complex DigitalOcean-specific setup back to a **clean, standard Docker deployment** that works with **any platform**.
|
||||||
|
|
||||||
|
## 🗑️ Removed Files
|
||||||
|
|
||||||
|
### Complex Infrastructure Files:
|
||||||
|
- ❌ `docker-compose.prod.yml` - Complex production setup
|
||||||
|
- ❌ `env.production` - Production environment file
|
||||||
|
- ❌ `nginx/nginx.conf` - Custom nginx configuration
|
||||||
|
- ❌ `nginx/conf.d/scriptshare.conf` - Site-specific nginx config
|
||||||
|
- ❌ `nginx/` directory - Removed entirely
|
||||||
|
|
||||||
|
### Management Scripts:
|
||||||
|
- ❌ `scripts/deploy.sh` - Complex deployment automation
|
||||||
|
- ❌ `scripts/backup.sh` - Database backup scripts
|
||||||
|
- ❌ `scripts/init-db.sql` - Database initialization
|
||||||
|
- ❌ `scripts/manage.sh` - Linux/macOS management
|
||||||
|
- ❌ `scripts/manage.ps1` - Windows PowerShell management
|
||||||
|
|
||||||
|
### Documentation:
|
||||||
|
- ❌ `DOCKER_DEPLOYMENT.md` - Complex deployment guide
|
||||||
|
- ❌ `README_DEPLOYMENT.md` - Deployment summary
|
||||||
|
- ❌ `DEPLOYMENT_SUCCESS.md` - DigitalOcean success page
|
||||||
|
- ❌ `.github/workflows/deploy.yml` - DigitalOcean workflow
|
||||||
|
|
||||||
|
## ✅ What You Now Have
|
||||||
|
|
||||||
|
### 🐳 Clean Docker Setup:
|
||||||
|
- **`Dockerfile`** - Simple frontend build (React + Nginx)
|
||||||
|
- **`Dockerfile.api`** - Clean API server (Node.js + Express)
|
||||||
|
- **`docker-compose.yml`** - Basic local development setup
|
||||||
|
- **`src/server.ts`** - Standalone API server
|
||||||
|
|
||||||
|
### 📚 Universal Documentation:
|
||||||
|
- **`DEPLOYMENT.md`** - Platform-agnostic deployment guide
|
||||||
|
- **`.github/workflows/build.yml`** - Universal CI/CD pipeline
|
||||||
|
|
||||||
|
### 🚀 Platform Compatibility:
|
||||||
|
- ✅ **Vercel** - Frontend deployment ready
|
||||||
|
- ✅ **Coolify** - Full Docker deployment
|
||||||
|
- ✅ **DigitalOcean App Platform** - Docker + app.yaml
|
||||||
|
- ✅ **Railway** - Auto-detect Docker builds
|
||||||
|
- ✅ **Render** - Static + web service deployment
|
||||||
|
- ✅ **Any Docker platform** - Standard Dockerfiles
|
||||||
|
|
||||||
|
## 🏗️ Current Architecture
|
||||||
|
|
||||||
|
```
|
||||||
|
Simple & Clean:
|
||||||
|
|
||||||
|
Frontend (Dockerfile) API (Dockerfile.api)
|
||||||
|
┌─────────────────┐ ┌─────────────────┐
|
||||||
|
│ React + Vite │ │ Node.js Express │
|
||||||
|
│ Built to Dist │ │ TypeScript │
|
||||||
|
│ Served by │ │ Port 3000 │
|
||||||
|
│ Nginx │ │ /api/health │
|
||||||
|
│ Port 80 │ └─────────────────┘
|
||||||
|
└─────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🚀 Quick Deployment Options
|
||||||
|
|
||||||
|
### Option 1: Vercel (Frontend)
|
||||||
|
```bash
|
||||||
|
vercel --prod
|
||||||
|
```
|
||||||
|
|
||||||
|
### Option 2: Coolify (Full Stack)
|
||||||
|
- Import from Git
|
||||||
|
- Auto-detect Dockerfiles
|
||||||
|
- Deploy both services
|
||||||
|
|
||||||
|
### Option 3: DigitalOcean App Platform
|
||||||
|
- Create app.yaml (see DEPLOYMENT.md)
|
||||||
|
- Deploy from repository
|
||||||
|
|
||||||
|
### Option 4: Railway
|
||||||
|
- Connect repository
|
||||||
|
- Auto-deploy both services
|
||||||
|
|
||||||
|
### Option 5: Docker Compose (Local)
|
||||||
|
```bash
|
||||||
|
docker-compose up
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🎯 Benefits of This Approach
|
||||||
|
|
||||||
|
### ✅ **Platform Agnostic**
|
||||||
|
- Works with **any** deployment platform
|
||||||
|
- No vendor lock-in
|
||||||
|
- Standard Docker practices
|
||||||
|
|
||||||
|
### ✅ **Simple & Clean**
|
||||||
|
- Minimal configuration
|
||||||
|
- Easy to understand
|
||||||
|
- Standard build processes
|
||||||
|
|
||||||
|
### ✅ **Flexible**
|
||||||
|
- Deploy frontend and API separately
|
||||||
|
- Scale components independently
|
||||||
|
- Choose best platform for each service
|
||||||
|
|
||||||
|
### ✅ **Maintainable**
|
||||||
|
- No complex orchestration
|
||||||
|
- Standard Docker patterns
|
||||||
|
- Platform-native features
|
||||||
|
|
||||||
|
## 📝 Next Steps
|
||||||
|
|
||||||
|
1. **Choose Your Platform**: Vercel, Coolify, Railway, Render, etc.
|
||||||
|
2. **Configure Environment Variables**: See DEPLOYMENT.md
|
||||||
|
3. **Deploy**: Follow platform-specific instructions
|
||||||
|
4. **Monitor**: Use platform-native monitoring tools
|
||||||
|
|
||||||
|
## 🎉 Summary
|
||||||
|
|
||||||
|
Your ScriptShare application is now **clean, simple, and ready for deployment on any modern platform**. The complex Docker Compose setup has been removed in favor of standard Dockerfiles that work everywhere.
|
||||||
|
|
||||||
|
**Key Files:**
|
||||||
|
- `Dockerfile` - Frontend build
|
||||||
|
- `Dockerfile.api` - API server
|
||||||
|
- `DEPLOYMENT.md` - Platform guide
|
||||||
|
- `src/server.ts` - API entry point
|
||||||
|
|
||||||
|
**Ready for:** Vercel, Coolify, DigitalOcean, Railway, Render, and any Docker platform!
|
@ -1,156 +0,0 @@
|
|||||||
version: '3.8'
|
|
||||||
|
|
||||||
services:
|
|
||||||
# MySQL Database
|
|
||||||
scriptshare-db:
|
|
||||||
image: mysql:8.0
|
|
||||||
container_name: scriptshare-db
|
|
||||||
restart: unless-stopped
|
|
||||||
environment:
|
|
||||||
MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD:-ScriptShare_Root_2024_Secure_Password}
|
|
||||||
MYSQL_DATABASE: ${DB_NAME:-scriptshare}
|
|
||||||
MYSQL_USER: ${DB_USER:-scriptshare_user}
|
|
||||||
MYSQL_PASSWORD: ${DB_PASSWORD:-ScriptShare_App_2024_Secure!}
|
|
||||||
MYSQL_CHARSET: utf8mb4
|
|
||||||
MYSQL_COLLATION: utf8mb4_unicode_ci
|
|
||||||
volumes:
|
|
||||||
- scriptshare_db_data:/var/lib/mysql
|
|
||||||
- ./scripts/init-db.sql:/docker-entrypoint-initdb.d/init-db.sql:ro
|
|
||||||
ports:
|
|
||||||
- "${DB_PORT:-3306}:3306"
|
|
||||||
networks:
|
|
||||||
- scriptshare-network
|
|
||||||
healthcheck:
|
|
||||||
test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-p${DB_ROOT_PASSWORD:-ScriptShare_Root_2024_Secure_Password}"]
|
|
||||||
interval: 30s
|
|
||||||
timeout: 10s
|
|
||||||
retries: 5
|
|
||||||
start_period: 60s
|
|
||||||
command: >
|
|
||||||
--default-authentication-plugin=mysql_native_password
|
|
||||||
--character-set-server=utf8mb4
|
|
||||||
--collation-server=utf8mb4_unicode_ci
|
|
||||||
--innodb-file-per-table=1
|
|
||||||
--max-connections=200
|
|
||||||
|
|
||||||
# Backend API
|
|
||||||
scriptshare-api:
|
|
||||||
build:
|
|
||||||
context: .
|
|
||||||
dockerfile: Dockerfile.api
|
|
||||||
container_name: scriptshare-api
|
|
||||||
restart: unless-stopped
|
|
||||||
environment:
|
|
||||||
- NODE_ENV=production
|
|
||||||
- DATABASE_URL=mysql://${DB_USER:-scriptshare_user}:${DB_PASSWORD:-ScriptShare_App_2024_Secure!}@scriptshare-db:3306/${DB_NAME:-scriptshare}
|
|
||||||
- JWT_SECRET=${JWT_SECRET:-production-super-secret-jwt-key-scriptshare-2024-secure}
|
|
||||||
- CORS_ORIGIN=${FRONTEND_URL:-http://localhost}
|
|
||||||
- PORT=3000
|
|
||||||
- DB_HOST=scriptshare-db
|
|
||||||
- DB_PORT=3306
|
|
||||||
- DB_USER=${DB_USER:-scriptshare_user}
|
|
||||||
- DB_PASSWORD=${DB_PASSWORD:-ScriptShare_App_2024_Secure!}
|
|
||||||
- DB_NAME=${DB_NAME:-scriptshare}
|
|
||||||
ports:
|
|
||||||
- "${API_PORT:-3001}:3000"
|
|
||||||
networks:
|
|
||||||
- scriptshare-network
|
|
||||||
depends_on:
|
|
||||||
scriptshare-db:
|
|
||||||
condition: service_healthy
|
|
||||||
healthcheck:
|
|
||||||
test: ["CMD", "curl", "-f", "http://localhost:3000/api/health"]
|
|
||||||
interval: 30s
|
|
||||||
timeout: 10s
|
|
||||||
retries: 3
|
|
||||||
start_period: 60s
|
|
||||||
volumes:
|
|
||||||
- scriptshare_api_logs:/app/logs
|
|
||||||
|
|
||||||
# Frontend
|
|
||||||
scriptshare-frontend:
|
|
||||||
build:
|
|
||||||
context: .
|
|
||||||
dockerfile: Dockerfile
|
|
||||||
args:
|
|
||||||
- VITE_APP_NAME=${APP_NAME:-ScriptShare}
|
|
||||||
- VITE_APP_URL=${APP_URL:-https://scriptshare.example.com}
|
|
||||||
- VITE_ANALYTICS_ENABLED=${ANALYTICS_ENABLED:-false}
|
|
||||||
- VITE_API_URL=${API_URL:-http://localhost:3001}
|
|
||||||
container_name: scriptshare-frontend
|
|
||||||
restart: unless-stopped
|
|
||||||
ports:
|
|
||||||
- "${FRONTEND_PORT:-80}:80"
|
|
||||||
networks:
|
|
||||||
- scriptshare-network
|
|
||||||
depends_on:
|
|
||||||
- scriptshare-api
|
|
||||||
healthcheck:
|
|
||||||
test: ["CMD", "curl", "-f", "http://localhost/"]
|
|
||||||
interval: 30s
|
|
||||||
timeout: 10s
|
|
||||||
retries: 3
|
|
||||||
start_period: 40s
|
|
||||||
volumes:
|
|
||||||
- scriptshare_frontend_logs:/var/log/nginx
|
|
||||||
|
|
||||||
# Reverse Proxy (Nginx)
|
|
||||||
scriptshare-proxy:
|
|
||||||
image: nginx:alpine
|
|
||||||
container_name: scriptshare-proxy
|
|
||||||
restart: unless-stopped
|
|
||||||
ports:
|
|
||||||
- "${PROXY_PORT:-8080}:80"
|
|
||||||
- "${PROXY_SSL_PORT:-8443}:443"
|
|
||||||
volumes:
|
|
||||||
- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
|
|
||||||
- ./nginx/conf.d:/etc/nginx/conf.d:ro
|
|
||||||
- scriptshare_proxy_logs:/var/log/nginx
|
|
||||||
- ${SSL_CERT_PATH:-./certs}:/etc/nginx/certs:ro
|
|
||||||
networks:
|
|
||||||
- scriptshare-network
|
|
||||||
depends_on:
|
|
||||||
- scriptshare-frontend
|
|
||||||
- scriptshare-api
|
|
||||||
healthcheck:
|
|
||||||
test: ["CMD", "curl", "-f", "http://localhost/health"]
|
|
||||||
interval: 30s
|
|
||||||
timeout: 10s
|
|
||||||
retries: 3
|
|
||||||
|
|
||||||
# Redis Cache (Optional)
|
|
||||||
scriptshare-redis:
|
|
||||||
image: redis:7-alpine
|
|
||||||
container_name: scriptshare-redis
|
|
||||||
restart: unless-stopped
|
|
||||||
command: redis-server --appendonly yes --requirepass ${REDIS_PASSWORD:-ScriptShare_Redis_2024}
|
|
||||||
ports:
|
|
||||||
- "${REDIS_PORT:-6379}:6379"
|
|
||||||
volumes:
|
|
||||||
- scriptshare_redis_data:/data
|
|
||||||
networks:
|
|
||||||
- scriptshare-network
|
|
||||||
healthcheck:
|
|
||||||
test: ["CMD", "redis-cli", "--raw", "incr", "ping"]
|
|
||||||
interval: 30s
|
|
||||||
timeout: 10s
|
|
||||||
retries: 3
|
|
||||||
|
|
||||||
volumes:
|
|
||||||
scriptshare_db_data:
|
|
||||||
driver: local
|
|
||||||
scriptshare_api_logs:
|
|
||||||
driver: local
|
|
||||||
scriptshare_frontend_logs:
|
|
||||||
driver: local
|
|
||||||
scriptshare_proxy_logs:
|
|
||||||
driver: local
|
|
||||||
scriptshare_redis_data:
|
|
||||||
driver: local
|
|
||||||
|
|
||||||
networks:
|
|
||||||
scriptshare-network:
|
|
||||||
driver: bridge
|
|
||||||
ipam:
|
|
||||||
config:
|
|
||||||
- subnet: 172.20.0.0/16
|
|
@ -1,52 +0,0 @@
|
|||||||
# ScriptShare Production Environment Configuration
|
|
||||||
|
|
||||||
# Application Settings
|
|
||||||
APP_NAME=ScriptShare
|
|
||||||
APP_URL=https://your-domain.com
|
|
||||||
ANALYTICS_ENABLED=true
|
|
||||||
NODE_ENV=production
|
|
||||||
|
|
||||||
# Database Configuration
|
|
||||||
DB_HOST=scriptshare-db
|
|
||||||
DB_PORT=3306
|
|
||||||
DB_NAME=scriptshare
|
|
||||||
DB_USER=scriptshare_user
|
|
||||||
DB_PASSWORD=ScriptShare_App_2024_Secure!
|
|
||||||
DB_ROOT_PASSWORD=ScriptShare_Root_2024_Secure_Password
|
|
||||||
DATABASE_URL=mysql://scriptshare_user:ScriptShare_App_2024_Secure!@scriptshare-db:3306/scriptshare
|
|
||||||
|
|
||||||
# Security
|
|
||||||
JWT_SECRET=production-super-secret-jwt-key-scriptshare-2024-secure-change-this-in-production
|
|
||||||
|
|
||||||
# API Configuration
|
|
||||||
API_PORT=3001
|
|
||||||
API_URL=http://localhost:3001
|
|
||||||
CORS_ORIGIN=https://your-domain.com
|
|
||||||
|
|
||||||
# Frontend Configuration
|
|
||||||
FRONTEND_PORT=80
|
|
||||||
FRONTEND_URL=https://your-domain.com
|
|
||||||
VITE_APP_NAME=ScriptShare
|
|
||||||
VITE_APP_URL=https://your-domain.com
|
|
||||||
VITE_ANALYTICS_ENABLED=true
|
|
||||||
VITE_API_URL=https://your-domain.com/api
|
|
||||||
|
|
||||||
# Proxy Configuration
|
|
||||||
PROXY_PORT=8080
|
|
||||||
PROXY_SSL_PORT=8443
|
|
||||||
|
|
||||||
# Redis Configuration (Optional)
|
|
||||||
REDIS_PORT=6379
|
|
||||||
REDIS_PASSWORD=ScriptShare_Redis_2024
|
|
||||||
|
|
||||||
# SSL Configuration
|
|
||||||
SSL_CERT_PATH=./certs
|
|
||||||
|
|
||||||
# Logging
|
|
||||||
LOG_LEVEL=info
|
|
||||||
LOG_FILE=/app/logs/scriptshare.log
|
|
||||||
|
|
||||||
# Backup Configuration
|
|
||||||
BACKUP_ENABLED=true
|
|
||||||
BACKUP_SCHEDULE=0 2 * * *
|
|
||||||
BACKUP_RETENTION_DAYS=30
|
|
@ -1,129 +0,0 @@
|
|||||||
# ScriptShare Main Configuration
|
|
||||||
upstream scriptshare_api {
|
|
||||||
server scriptshare-api:3000;
|
|
||||||
}
|
|
||||||
|
|
||||||
upstream scriptshare_frontend {
|
|
||||||
server scriptshare-frontend:80;
|
|
||||||
}
|
|
||||||
|
|
||||||
# HTTP to HTTPS redirect (when SSL is configured)
|
|
||||||
server {
|
|
||||||
listen 80;
|
|
||||||
server_name _;
|
|
||||||
|
|
||||||
# Health check endpoint
|
|
||||||
location /health {
|
|
||||||
access_log off;
|
|
||||||
return 200 "healthy\n";
|
|
||||||
add_header Content-Type text/plain;
|
|
||||||
}
|
|
||||||
|
|
||||||
# API routes
|
|
||||||
location /api/ {
|
|
||||||
# Rate limiting for API
|
|
||||||
limit_req zone=api burst=20 nodelay;
|
|
||||||
|
|
||||||
# Proxy headers
|
|
||||||
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 settings
|
|
||||||
proxy_pass http://scriptshare_api;
|
|
||||||
proxy_redirect off;
|
|
||||||
proxy_buffering off;
|
|
||||||
proxy_read_timeout 60s;
|
|
||||||
proxy_connect_timeout 60s;
|
|
||||||
proxy_send_timeout 60s;
|
|
||||||
|
|
||||||
# CORS headers (if needed)
|
|
||||||
add_header 'Access-Control-Allow-Origin' '*' always;
|
|
||||||
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS' always;
|
|
||||||
add_header 'Access-Control-Allow-Headers' 'Accept,Authorization,Cache-Control,Content-Type,DNT,If-Modified-Since,Keep-Alive,Origin,User-Agent,X-Requested-With,X-User-Id' always;
|
|
||||||
|
|
||||||
# Handle preflight requests
|
|
||||||
if ($request_method = 'OPTIONS') {
|
|
||||||
add_header 'Access-Control-Allow-Origin' '*';
|
|
||||||
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS';
|
|
||||||
add_header 'Access-Control-Allow-Headers' 'Accept,Authorization,Cache-Control,Content-Type,DNT,If-Modified-Since,Keep-Alive,Origin,User-Agent,X-Requested-With,X-User-Id';
|
|
||||||
add_header 'Access-Control-Max-Age' 1728000;
|
|
||||||
add_header 'Content-Type' 'text/plain; charset=utf-8';
|
|
||||||
add_header 'Content-Length' 0;
|
|
||||||
return 204;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# Special rate limiting for auth endpoints
|
|
||||||
location /api/auth/ {
|
|
||||||
limit_req zone=login burst=5 nodelay;
|
|
||||||
|
|
||||||
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_pass http://scriptshare_api;
|
|
||||||
proxy_redirect off;
|
|
||||||
proxy_buffering off;
|
|
||||||
proxy_read_timeout 60s;
|
|
||||||
proxy_connect_timeout 60s;
|
|
||||||
proxy_send_timeout 60s;
|
|
||||||
}
|
|
||||||
|
|
||||||
# Frontend routes
|
|
||||||
location / {
|
|
||||||
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_pass http://scriptshare_frontend;
|
|
||||||
proxy_redirect off;
|
|
||||||
|
|
||||||
# Handle SPA routing
|
|
||||||
try_files $uri $uri/ @fallback;
|
|
||||||
}
|
|
||||||
|
|
||||||
# Fallback for SPA routing
|
|
||||||
location @fallback {
|
|
||||||
proxy_pass http://scriptshare_frontend;
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
# Static assets caching
|
|
||||||
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
|
|
||||||
proxy_pass http://scriptshare_frontend;
|
|
||||||
proxy_cache_valid 200 1y;
|
|
||||||
add_header Cache-Control "public, immutable";
|
|
||||||
expires 1y;
|
|
||||||
}
|
|
||||||
|
|
||||||
# Security headers
|
|
||||||
add_header X-Frame-Options "SAMEORIGIN" always;
|
|
||||||
add_header X-Content-Type-Options "nosniff" always;
|
|
||||||
add_header X-XSS-Protection "1; mode=block" always;
|
|
||||||
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
|
|
||||||
|
|
||||||
# Hide nginx version
|
|
||||||
server_tokens off;
|
|
||||||
}
|
|
||||||
|
|
||||||
# HTTPS Configuration (uncomment and configure when SSL certificates are ready)
|
|
||||||
# server {
|
|
||||||
# listen 443 ssl http2;
|
|
||||||
# server_name your-domain.com;
|
|
||||||
#
|
|
||||||
# ssl_certificate /etc/nginx/certs/fullchain.pem;
|
|
||||||
# ssl_certificate_key /etc/nginx/certs/privkey.pem;
|
|
||||||
# ssl_protocols TLSv1.2 TLSv1.3;
|
|
||||||
# ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384;
|
|
||||||
# ssl_prefer_server_ciphers off;
|
|
||||||
#
|
|
||||||
# # Include the same location blocks as above
|
|
||||||
# include /etc/nginx/conf.d/common-locations.conf;
|
|
||||||
# }
|
|
@ -1,47 +0,0 @@
|
|||||||
events {
|
|
||||||
worker_connections 1024;
|
|
||||||
}
|
|
||||||
|
|
||||||
http {
|
|
||||||
include /etc/nginx/mime.types;
|
|
||||||
default_type application/octet-stream;
|
|
||||||
|
|
||||||
# Logging format
|
|
||||||
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
|
|
||||||
'$status $body_bytes_sent "$http_referer" '
|
|
||||||
'"$http_user_agent" "$http_x_forwarded_for"';
|
|
||||||
|
|
||||||
access_log /var/log/nginx/access.log main;
|
|
||||||
error_log /var/log/nginx/error.log warn;
|
|
||||||
|
|
||||||
# Performance settings
|
|
||||||
sendfile on;
|
|
||||||
tcp_nopush on;
|
|
||||||
tcp_nodelay on;
|
|
||||||
keepalive_timeout 65;
|
|
||||||
types_hash_max_size 2048;
|
|
||||||
client_max_body_size 10M;
|
|
||||||
|
|
||||||
# Gzip compression
|
|
||||||
gzip on;
|
|
||||||
gzip_vary on;
|
|
||||||
gzip_min_length 1000;
|
|
||||||
gzip_types
|
|
||||||
text/plain
|
|
||||||
text/css
|
|
||||||
text/xml
|
|
||||||
text/javascript
|
|
||||||
application/json
|
|
||||||
application/javascript
|
|
||||||
application/xml
|
|
||||||
application/rss+xml
|
|
||||||
application/atom+xml
|
|
||||||
image/svg+xml;
|
|
||||||
|
|
||||||
# Rate limiting
|
|
||||||
limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;
|
|
||||||
limit_req_zone $binary_remote_addr zone=login:10m rate=5r/m;
|
|
||||||
|
|
||||||
# Include additional configurations
|
|
||||||
include /etc/nginx/conf.d/*.conf;
|
|
||||||
}
|
|
@ -1,53 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
# ScriptShare Database Backup Script
|
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
# Load environment variables
|
|
||||||
if [ -f ".env" ]; then
|
|
||||||
source .env
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Default values
|
|
||||||
DB_CONTAINER=${DB_CONTAINER:-scriptshare-db}
|
|
||||||
BACKUP_DIR=${BACKUP_DIR:-./backups}
|
|
||||||
RETENTION_DAYS=${BACKUP_RETENTION_DAYS:-30}
|
|
||||||
|
|
||||||
# Create backup directory
|
|
||||||
mkdir -p "$BACKUP_DIR"
|
|
||||||
|
|
||||||
# Generate backup filename with timestamp
|
|
||||||
TIMESTAMP=$(date +"%Y%m%d_%H%M%S")
|
|
||||||
BACKUP_FILE="$BACKUP_DIR/scriptshare_backup_$TIMESTAMP.sql"
|
|
||||||
|
|
||||||
echo "🗄️ Starting database backup..."
|
|
||||||
echo "Backup file: $BACKUP_FILE"
|
|
||||||
|
|
||||||
# Create database backup
|
|
||||||
docker exec "$DB_CONTAINER" mysqldump \
|
|
||||||
--single-transaction \
|
|
||||||
--routines \
|
|
||||||
--triggers \
|
|
||||||
--all-databases \
|
|
||||||
-u root \
|
|
||||||
-p"${DB_ROOT_PASSWORD}" > "$BACKUP_FILE"
|
|
||||||
|
|
||||||
# Compress the backup
|
|
||||||
gzip "$BACKUP_FILE"
|
|
||||||
BACKUP_FILE="$BACKUP_FILE.gz"
|
|
||||||
|
|
||||||
echo "✅ Database backup completed: $BACKUP_FILE"
|
|
||||||
|
|
||||||
# Calculate backup size
|
|
||||||
BACKUP_SIZE=$(du -h "$BACKUP_FILE" | cut -f1)
|
|
||||||
echo "📦 Backup size: $BACKUP_SIZE"
|
|
||||||
|
|
||||||
# Clean up old backups
|
|
||||||
echo "🧹 Cleaning up old backups (older than $RETENTION_DAYS days)..."
|
|
||||||
find "$BACKUP_DIR" -name "scriptshare_backup_*.sql.gz" -mtime +$RETENTION_DAYS -delete
|
|
||||||
|
|
||||||
# List remaining backups
|
|
||||||
echo "📋 Current backups:"
|
|
||||||
ls -lh "$BACKUP_DIR"/scriptshare_backup_*.sql.gz 2>/dev/null || echo "No backups found"
|
|
||||||
|
|
||||||
echo "✅ Backup process completed successfully!"
|
|
@ -1,92 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
# ScriptShare Production Deployment Script
|
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
echo "🚀 Starting ScriptShare deployment..."
|
|
||||||
|
|
||||||
# Check if Docker and Docker Compose are installed
|
|
||||||
if ! command -v docker &> /dev/null; then
|
|
||||||
echo "❌ Docker is not installed. Please install Docker first."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if ! command -v docker-compose &> /dev/null && ! docker compose version &> /dev/null; then
|
|
||||||
echo "❌ Docker Compose is not installed. Please install Docker Compose first."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Check if environment file exists
|
|
||||||
if [ ! -f "env.production" ]; then
|
|
||||||
echo "❌ Environment file 'env.production' not found."
|
|
||||||
echo "Please copy 'env.production' and configure your settings."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Create necessary directories
|
|
||||||
echo "📁 Creating required directories..."
|
|
||||||
mkdir -p logs
|
|
||||||
mkdir -p certs
|
|
||||||
mkdir -p backups
|
|
||||||
|
|
||||||
# Copy environment file
|
|
||||||
cp env.production .env
|
|
||||||
|
|
||||||
# Pull latest images
|
|
||||||
echo "📥 Pulling Docker images..."
|
|
||||||
docker-compose -f docker-compose.prod.yml pull
|
|
||||||
|
|
||||||
# Build custom images
|
|
||||||
echo "🔨 Building application images..."
|
|
||||||
docker-compose -f docker-compose.prod.yml build --no-cache
|
|
||||||
|
|
||||||
# Stop existing containers if running
|
|
||||||
echo "🛑 Stopping existing containers..."
|
|
||||||
docker-compose -f docker-compose.prod.yml down
|
|
||||||
|
|
||||||
# Start the application
|
|
||||||
echo "🚀 Starting ScriptShare application..."
|
|
||||||
docker-compose -f docker-compose.prod.yml up -d
|
|
||||||
|
|
||||||
# Wait for services to be healthy
|
|
||||||
echo "⏳ Waiting for services to start..."
|
|
||||||
sleep 30
|
|
||||||
|
|
||||||
# Check service health
|
|
||||||
echo "🏥 Checking service health..."
|
|
||||||
services=("scriptshare-db" "scriptshare-api" "scriptshare-frontend" "scriptshare-proxy")
|
|
||||||
|
|
||||||
for service in "${services[@]}"; do
|
|
||||||
if docker-compose -f docker-compose.prod.yml ps | grep -q "$service.*Up"; then
|
|
||||||
echo "✅ $service is running"
|
|
||||||
else
|
|
||||||
echo "❌ $service failed to start"
|
|
||||||
echo "Checking logs for $service:"
|
|
||||||
docker-compose -f docker-compose.prod.yml logs "$service"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
# Run database migrations if needed
|
|
||||||
echo "🗃️ Running database migrations..."
|
|
||||||
docker-compose -f docker-compose.prod.yml exec -T scriptshare-api npm run db:migrate:prod || echo "⚠️ Database migrations not available or failed"
|
|
||||||
|
|
||||||
# Display deployment information
|
|
||||||
echo ""
|
|
||||||
echo "🎉 ScriptShare deployment completed successfully!"
|
|
||||||
echo ""
|
|
||||||
echo "📊 Service URLs:"
|
|
||||||
echo " Frontend: http://localhost:$(grep PROXY_PORT .env | cut -d'=' -f2 | tr -d '"')"
|
|
||||||
echo " API: http://localhost:$(grep API_PORT .env | cut -d'=' -f2 | tr -d '"')/api/health"
|
|
||||||
echo " Database: localhost:$(grep DB_PORT .env | cut -d'=' -f2 | tr -d '"')"
|
|
||||||
echo ""
|
|
||||||
echo "🔧 Management commands:"
|
|
||||||
echo " View logs: docker-compose -f docker-compose.prod.yml logs -f"
|
|
||||||
echo " Stop: docker-compose -f docker-compose.prod.yml down"
|
|
||||||
echo " Restart: docker-compose -f docker-compose.prod.yml restart"
|
|
||||||
echo ""
|
|
||||||
echo "📝 Next steps:"
|
|
||||||
echo " 1. Configure your domain DNS to point to this server"
|
|
||||||
echo " 2. Set up SSL certificates in ./certs/"
|
|
||||||
echo " 3. Update env.production with your domain settings"
|
|
||||||
echo " 4. Run: docker-compose -f docker-compose.prod.yml restart scriptshare-proxy"
|
|
@ -1,47 +0,0 @@
|
|||||||
-- ScriptShare Database Initialization Script
|
|
||||||
-- This script sets up the initial database structure and default data
|
|
||||||
|
|
||||||
USE scriptshare;
|
|
||||||
|
|
||||||
-- Create tables if they don't exist (will be handled by Drizzle migrations)
|
|
||||||
-- This file can be used for any initial data setup
|
|
||||||
|
|
||||||
-- Insert default admin user (optional)
|
|
||||||
-- Note: Password should be properly hashed in production
|
|
||||||
INSERT IGNORE INTO users (id, email, username, displayName, isAdmin, isModerator, createdAt, updatedAt)
|
|
||||||
VALUES (
|
|
||||||
'admin-default-id',
|
|
||||||
'admin@scriptshare.local',
|
|
||||||
'admin',
|
|
||||||
'Administrator',
|
|
||||||
true,
|
|
||||||
true,
|
|
||||||
NOW(),
|
|
||||||
NOW()
|
|
||||||
);
|
|
||||||
|
|
||||||
-- Insert sample categories
|
|
||||||
INSERT IGNORE INTO script_categories (name, description) VALUES
|
|
||||||
('System Administration', 'Scripts for system administration tasks'),
|
|
||||||
('Development', 'Development and build automation scripts'),
|
|
||||||
('Backup & Recovery', 'Backup and recovery automation'),
|
|
||||||
('Monitoring', 'System and application monitoring scripts'),
|
|
||||||
('Security', 'Security and audit scripts'),
|
|
||||||
('Database', 'Database management and maintenance'),
|
|
||||||
('Network', 'Network configuration and management'),
|
|
||||||
('DevOps', 'DevOps and CI/CD automation');
|
|
||||||
|
|
||||||
-- Create indexes for performance
|
|
||||||
CREATE INDEX IF NOT EXISTS idx_scripts_author ON scripts(authorId);
|
|
||||||
CREATE INDEX IF NOT EXISTS idx_scripts_created ON scripts(createdAt);
|
|
||||||
CREATE INDEX IF NOT EXISTS idx_scripts_approved ON scripts(isApproved);
|
|
||||||
CREATE INDEX IF NOT EXISTS idx_ratings_script ON ratings(scriptId);
|
|
||||||
CREATE INDEX IF NOT EXISTS idx_analytics_script ON script_analytics(scriptId);
|
|
||||||
CREATE INDEX IF NOT EXISTS idx_analytics_created ON script_analytics(createdAt);
|
|
||||||
|
|
||||||
-- Set up database optimization
|
|
||||||
SET GLOBAL innodb_buffer_pool_size = 268435456; -- 256MB
|
|
||||||
SET GLOBAL max_connections = 200;
|
|
||||||
|
|
||||||
-- Print initialization complete message
|
|
||||||
SELECT 'ScriptShare database initialization completed!' as message;
|
|
@ -1,142 +0,0 @@
|
|||||||
# ScriptShare Management Script for Windows PowerShell
|
|
||||||
|
|
||||||
param(
|
|
||||||
[Parameter(Mandatory=$true, Position=0)]
|
|
||||||
[string]$Command,
|
|
||||||
[Parameter(Position=1)]
|
|
||||||
[string]$Service
|
|
||||||
)
|
|
||||||
|
|
||||||
$ComposeFile = "docker-compose.prod.yml"
|
|
||||||
|
|
||||||
function Show-Help {
|
|
||||||
Write-Host "ScriptShare Management Script" -ForegroundColor Green
|
|
||||||
Write-Host ""
|
|
||||||
Write-Host "Usage: .\scripts\manage.ps1 [COMMAND] [SERVICE]" -ForegroundColor Yellow
|
|
||||||
Write-Host ""
|
|
||||||
Write-Host "Commands:" -ForegroundColor Cyan
|
|
||||||
Write-Host " start Start all services"
|
|
||||||
Write-Host " stop Stop all services"
|
|
||||||
Write-Host " restart Restart all services"
|
|
||||||
Write-Host " logs Show logs for all services"
|
|
||||||
Write-Host " logs [svc] Show logs for specific service"
|
|
||||||
Write-Host " status Show status of all services"
|
|
||||||
Write-Host " backup Create database backup"
|
|
||||||
Write-Host " update Update application (pull, build, restart)"
|
|
||||||
Write-Host " clean Clean up unused Docker resources"
|
|
||||||
Write-Host " shell [svc] Open shell in service container"
|
|
||||||
Write-Host " db Connect to database"
|
|
||||||
Write-Host " help Show this help message"
|
|
||||||
Write-Host ""
|
|
||||||
Write-Host "Services: scriptshare-db, scriptshare-api, scriptshare-frontend, scriptshare-proxy, scriptshare-redis" -ForegroundColor Gray
|
|
||||||
}
|
|
||||||
|
|
||||||
switch ($Command.ToLower()) {
|
|
||||||
"start" {
|
|
||||||
Write-Host "🚀 Starting ScriptShare services..." -ForegroundColor Green
|
|
||||||
docker-compose -f $ComposeFile up -d
|
|
||||||
Write-Host "✅ Services started" -ForegroundColor Green
|
|
||||||
}
|
|
||||||
|
|
||||||
"stop" {
|
|
||||||
Write-Host "🛑 Stopping ScriptShare services..." -ForegroundColor Yellow
|
|
||||||
docker-compose -f $ComposeFile down
|
|
||||||
Write-Host "✅ Services stopped" -ForegroundColor Green
|
|
||||||
}
|
|
||||||
|
|
||||||
"restart" {
|
|
||||||
Write-Host "🔄 Restarting ScriptShare services..." -ForegroundColor Yellow
|
|
||||||
docker-compose -f $ComposeFile restart
|
|
||||||
Write-Host "✅ Services restarted" -ForegroundColor Green
|
|
||||||
}
|
|
||||||
|
|
||||||
"logs" {
|
|
||||||
if ($Service) {
|
|
||||||
Write-Host "📋 Showing logs for $Service..." -ForegroundColor Cyan
|
|
||||||
docker-compose -f $ComposeFile logs -f $Service
|
|
||||||
} else {
|
|
||||||
Write-Host "📋 Showing logs for all services..." -ForegroundColor Cyan
|
|
||||||
docker-compose -f $ComposeFile logs -f
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
"status" {
|
|
||||||
Write-Host "📊 Service Status:" -ForegroundColor Cyan
|
|
||||||
docker-compose -f $ComposeFile ps
|
|
||||||
Write-Host ""
|
|
||||||
Write-Host "🏥 Health Status:" -ForegroundColor Cyan
|
|
||||||
$services = @("scriptshare-db", "scriptshare-api", "scriptshare-frontend", "scriptshare-proxy")
|
|
||||||
foreach ($svc in $services) {
|
|
||||||
try {
|
|
||||||
$health = docker inspect --format='{{.State.Health.Status}}' $svc 2>$null
|
|
||||||
if (-not $health) { $health = "not found" }
|
|
||||||
Write-Host " $svc`: $health" -ForegroundColor Gray
|
|
||||||
} catch {
|
|
||||||
Write-Host " $svc`: not found" -ForegroundColor Red
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
"backup" {
|
|
||||||
Write-Host "🗄️ Creating database backup..." -ForegroundColor Cyan
|
|
||||||
if (Test-Path ".\scripts\backup.sh") {
|
|
||||||
bash .\scripts\backup.sh
|
|
||||||
} else {
|
|
||||||
Write-Host "❌ Backup script not found. Please run manually:" -ForegroundColor Red
|
|
||||||
Write-Host "docker exec scriptshare-db mysqladmin ping" -ForegroundColor Gray
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
"update" {
|
|
||||||
Write-Host "🔄 Updating ScriptShare application..." -ForegroundColor Cyan
|
|
||||||
docker-compose -f $ComposeFile pull
|
|
||||||
docker-compose -f $ComposeFile build --no-cache
|
|
||||||
docker-compose -f $ComposeFile up -d
|
|
||||||
Write-Host "✅ Application updated" -ForegroundColor Green
|
|
||||||
}
|
|
||||||
|
|
||||||
"clean" {
|
|
||||||
Write-Host "🧹 Cleaning up Docker resources..." -ForegroundColor Yellow
|
|
||||||
docker system prune -f
|
|
||||||
docker volume prune -f
|
|
||||||
Write-Host "✅ Cleanup completed" -ForegroundColor Green
|
|
||||||
}
|
|
||||||
|
|
||||||
"shell" {
|
|
||||||
if (-not $Service) {
|
|
||||||
Write-Host "❌ Please specify service name" -ForegroundColor Red
|
|
||||||
Write-Host "Available services: scriptshare-db, scriptshare-api, scriptshare-frontend, scriptshare-proxy" -ForegroundColor Gray
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
Write-Host "💻 Opening shell in $Service..." -ForegroundColor Cyan
|
|
||||||
docker-compose -f $ComposeFile exec $Service /bin/sh
|
|
||||||
}
|
|
||||||
|
|
||||||
"db" {
|
|
||||||
Write-Host "🗃️ Connecting to database..." -ForegroundColor Cyan
|
|
||||||
$envFile = ".env"
|
|
||||||
$dbUser = "scriptshare_user"
|
|
||||||
$dbPassword = "ScriptShare_App_2024_Secure!"
|
|
||||||
$dbName = "scriptshare"
|
|
||||||
|
|
||||||
if (Test-Path $envFile) {
|
|
||||||
$env = Get-Content $envFile | ConvertFrom-StringData
|
|
||||||
if ($env.DB_USER) { $dbUser = $env.DB_USER }
|
|
||||||
if ($env.DB_PASSWORD) { $dbPassword = $env.DB_PASSWORD }
|
|
||||||
if ($env.DB_NAME) { $dbName = $env.DB_NAME }
|
|
||||||
}
|
|
||||||
|
|
||||||
docker-compose -f $ComposeFile exec scriptshare-db mysql -u $dbUser -p$dbPassword $dbName
|
|
||||||
}
|
|
||||||
|
|
||||||
"help" {
|
|
||||||
Show-Help
|
|
||||||
}
|
|
||||||
|
|
||||||
default {
|
|
||||||
Write-Host "❌ Unknown command: $Command" -ForegroundColor Red
|
|
||||||
Write-Host ""
|
|
||||||
Show-Help
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,130 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
# ScriptShare Management Script
|
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
COMPOSE_FILE="docker-compose.prod.yml"
|
|
||||||
|
|
||||||
show_help() {
|
|
||||||
echo "ScriptShare Management Script"
|
|
||||||
echo ""
|
|
||||||
echo "Usage: $0 [COMMAND]"
|
|
||||||
echo ""
|
|
||||||
echo "Commands:"
|
|
||||||
echo " start Start all services"
|
|
||||||
echo " stop Stop all services"
|
|
||||||
echo " restart Restart all services"
|
|
||||||
echo " logs Show logs for all services"
|
|
||||||
echo " logs [svc] Show logs for specific service"
|
|
||||||
echo " status Show status of all services"
|
|
||||||
echo " backup Create database backup"
|
|
||||||
echo " restore Restore database from backup"
|
|
||||||
echo " update Update application (pull, build, restart)"
|
|
||||||
echo " clean Clean up unused Docker resources"
|
|
||||||
echo " shell [svc] Open shell in service container"
|
|
||||||
echo " db Connect to database"
|
|
||||||
echo " help Show this help message"
|
|
||||||
echo ""
|
|
||||||
echo "Services: scriptshare-db, scriptshare-api, scriptshare-frontend, scriptshare-proxy, scriptshare-redis"
|
|
||||||
}
|
|
||||||
|
|
||||||
case "$1" in
|
|
||||||
start)
|
|
||||||
echo "🚀 Starting ScriptShare services..."
|
|
||||||
docker-compose -f "$COMPOSE_FILE" up -d
|
|
||||||
echo "✅ Services started"
|
|
||||||
;;
|
|
||||||
|
|
||||||
stop)
|
|
||||||
echo "🛑 Stopping ScriptShare services..."
|
|
||||||
docker-compose -f "$COMPOSE_FILE" down
|
|
||||||
echo "✅ Services stopped"
|
|
||||||
;;
|
|
||||||
|
|
||||||
restart)
|
|
||||||
echo "🔄 Restarting ScriptShare services..."
|
|
||||||
docker-compose -f "$COMPOSE_FILE" restart
|
|
||||||
echo "✅ Services restarted"
|
|
||||||
;;
|
|
||||||
|
|
||||||
logs)
|
|
||||||
if [ -n "$2" ]; then
|
|
||||||
echo "📋 Showing logs for $2..."
|
|
||||||
docker-compose -f "$COMPOSE_FILE" logs -f "$2"
|
|
||||||
else
|
|
||||||
echo "📋 Showing logs for all services..."
|
|
||||||
docker-compose -f "$COMPOSE_FILE" logs -f
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
|
|
||||||
status)
|
|
||||||
echo "📊 Service Status:"
|
|
||||||
docker-compose -f "$COMPOSE_FILE" ps
|
|
||||||
echo ""
|
|
||||||
echo "🏥 Health Status:"
|
|
||||||
for service in scriptshare-db scriptshare-api scriptshare-frontend scriptshare-proxy; do
|
|
||||||
health=$(docker inspect --format='{{.State.Health.Status}}' "$service" 2>/dev/null || echo "not found")
|
|
||||||
echo " $service: $health"
|
|
||||||
done
|
|
||||||
;;
|
|
||||||
|
|
||||||
backup)
|
|
||||||
echo "🗄️ Creating database backup..."
|
|
||||||
./scripts/backup.sh
|
|
||||||
;;
|
|
||||||
|
|
||||||
restore)
|
|
||||||
if [ -z "$2" ]; then
|
|
||||||
echo "❌ Please specify backup file to restore"
|
|
||||||
echo "Usage: $0 restore <backup-file>"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
echo "🔄 Restoring database from $2..."
|
|
||||||
# Implementation for restore would go here
|
|
||||||
echo "⚠️ Restore functionality not yet implemented"
|
|
||||||
;;
|
|
||||||
|
|
||||||
update)
|
|
||||||
echo "🔄 Updating ScriptShare application..."
|
|
||||||
docker-compose -f "$COMPOSE_FILE" pull
|
|
||||||
docker-compose -f "$COMPOSE_FILE" build --no-cache
|
|
||||||
docker-compose -f "$COMPOSE_FILE" up -d
|
|
||||||
echo "✅ Application updated"
|
|
||||||
;;
|
|
||||||
|
|
||||||
clean)
|
|
||||||
echo "🧹 Cleaning up Docker resources..."
|
|
||||||
docker system prune -f
|
|
||||||
docker volume prune -f
|
|
||||||
echo "✅ Cleanup completed"
|
|
||||||
;;
|
|
||||||
|
|
||||||
shell)
|
|
||||||
if [ -z "$2" ]; then
|
|
||||||
echo "❌ Please specify service name"
|
|
||||||
echo "Available services: scriptshare-db, scriptshare-api, scriptshare-frontend, scriptshare-proxy"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
echo "💻 Opening shell in $2..."
|
|
||||||
docker-compose -f "$COMPOSE_FILE" exec "$2" /bin/sh
|
|
||||||
;;
|
|
||||||
|
|
||||||
db)
|
|
||||||
echo "🗃️ Connecting to database..."
|
|
||||||
if [ -f ".env" ]; then
|
|
||||||
source .env
|
|
||||||
fi
|
|
||||||
docker-compose -f "$COMPOSE_FILE" exec scriptshare-db mysql -u "${DB_USER:-scriptshare_user}" -p"${DB_PASSWORD:-ScriptShare_App_2024_Secure!}" "${DB_NAME:-scriptshare}"
|
|
||||||
;;
|
|
||||||
|
|
||||||
help|--help|-h)
|
|
||||||
show_help
|
|
||||||
;;
|
|
||||||
|
|
||||||
*)
|
|
||||||
echo "❌ Unknown command: $1"
|
|
||||||
echo ""
|
|
||||||
show_help
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
esac
|
|
179
src/server.ts
Normal file
179
src/server.ts
Normal file
@ -0,0 +1,179 @@
|
|||||||
|
import express from 'express';
|
||||||
|
import cors from 'cors';
|
||||||
|
import { createUser, getUserByEmail, updateUser, getAllUsers, getUserById } from './lib/api/users.js';
|
||||||
|
import { getScripts, getScriptById, createScript, updateScript, deleteScript, moderateScript } from './lib/api/scripts.js';
|
||||||
|
import { login, register, refreshToken } from './lib/api/auth.js';
|
||||||
|
import { rateScript, getUserRating, getScriptRatingStats } from './lib/api/ratings.js';
|
||||||
|
import { getPlatformAnalytics, getScriptAnalytics, trackEvent } from './lib/api/analytics.js';
|
||||||
|
import { createCollection, getUserCollections, getPublicCollections, addScriptToCollection } from './lib/api/collections.js';
|
||||||
|
|
||||||
|
const app = express();
|
||||||
|
const PORT = process.env.PORT || 3000;
|
||||||
|
|
||||||
|
// Middleware
|
||||||
|
app.use(cors({
|
||||||
|
origin: process.env.CORS_ORIGIN || '*',
|
||||||
|
credentials: true
|
||||||
|
}));
|
||||||
|
app.use(express.json({ limit: '10mb' }));
|
||||||
|
app.use(express.urlencoded({ extended: true }));
|
||||||
|
|
||||||
|
// Health check endpoint
|
||||||
|
app.get('/api/health', (req, res) => {
|
||||||
|
res.json({ status: 'ok', timestamp: new Date().toISOString() });
|
||||||
|
});
|
||||||
|
|
||||||
|
// Auth routes
|
||||||
|
app.post('/api/auth/login', async (req, res) => {
|
||||||
|
try {
|
||||||
|
const result = await login(req.body);
|
||||||
|
res.json(result);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Login error:', error);
|
||||||
|
res.status(401).json({ error: 'Invalid credentials' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
app.post('/api/auth/register', async (req, res) => {
|
||||||
|
try {
|
||||||
|
const result = await register(req.body);
|
||||||
|
res.json(result);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Register error:', error);
|
||||||
|
res.status(400).json({ error: 'Registration failed' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Scripts routes
|
||||||
|
app.get('/api/scripts', async (req, res) => {
|
||||||
|
try {
|
||||||
|
const result = await getScripts(req.query);
|
||||||
|
res.json(result);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Get scripts error:', error);
|
||||||
|
res.status(500).json({ error: 'Failed to fetch scripts' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
app.get('/api/scripts/:id', async (req, res) => {
|
||||||
|
try {
|
||||||
|
const script = await getScriptById(req.params.id);
|
||||||
|
if (!script) {
|
||||||
|
return res.status(404).json({ error: 'Script not found' });
|
||||||
|
}
|
||||||
|
res.json(script);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Get script error:', error);
|
||||||
|
res.status(500).json({ error: 'Failed to fetch script' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
app.post('/api/scripts', async (req, res) => {
|
||||||
|
try {
|
||||||
|
const userId = req.headers['x-user-id'] as string;
|
||||||
|
if (!userId) {
|
||||||
|
return res.status(401).json({ error: 'Unauthorized' });
|
||||||
|
}
|
||||||
|
const result = await createScript(req.body, userId);
|
||||||
|
res.json(result);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Create script error:', error);
|
||||||
|
res.status(500).json({ error: 'Failed to create script' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Users routes
|
||||||
|
app.get('/api/users', async (req, res) => {
|
||||||
|
try {
|
||||||
|
const result = await getAllUsers();
|
||||||
|
res.json(result);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Get users error:', error);
|
||||||
|
res.status(500).json({ error: 'Failed to fetch users' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
app.get('/api/users/:id', async (req, res) => {
|
||||||
|
try {
|
||||||
|
const user = await getUserById(req.params.id);
|
||||||
|
if (!user) {
|
||||||
|
return res.status(404).json({ error: 'User not found' });
|
||||||
|
}
|
||||||
|
res.json(user);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Get user error:', error);
|
||||||
|
res.status(500).json({ error: 'Failed to fetch user' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Analytics routes
|
||||||
|
app.get('/api/analytics/platform', async (req, res) => {
|
||||||
|
try {
|
||||||
|
const days = parseInt(req.query.days as string) || 30;
|
||||||
|
const result = await getPlatformAnalytics(days);
|
||||||
|
res.json(result);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Analytics error:', error);
|
||||||
|
res.status(500).json({ error: 'Failed to fetch analytics' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
app.post('/api/analytics/track', async (req, res) => {
|
||||||
|
try {
|
||||||
|
const result = await trackEvent(req.body);
|
||||||
|
res.json(result);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Track event error:', error);
|
||||||
|
res.status(500).json({ error: 'Failed to track event' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Collections routes
|
||||||
|
app.get('/api/collections', async (req, res) => {
|
||||||
|
try {
|
||||||
|
const userId = req.headers['x-user-id'] as string;
|
||||||
|
const result = userId ? await getUserCollections(userId) : await getPublicCollections();
|
||||||
|
res.json(result);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Get collections error:', error);
|
||||||
|
res.status(500).json({ error: 'Failed to fetch collections' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Ratings routes
|
||||||
|
app.post('/api/ratings', async (req, res) => {
|
||||||
|
try {
|
||||||
|
const result = await rateScript(req.body);
|
||||||
|
res.json(result);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Rate script error:', error);
|
||||||
|
res.status(500).json({ error: 'Failed to rate script' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
app.get('/api/scripts/:id/ratings', async (req, res) => {
|
||||||
|
try {
|
||||||
|
const result = await getScriptRatingStats(req.params.id);
|
||||||
|
res.json(result);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Get ratings error:', error);
|
||||||
|
res.status(500).json({ error: 'Failed to fetch ratings' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Error handling middleware
|
||||||
|
app.use((error: any, req: express.Request, res: express.Response, next: express.NextFunction) => {
|
||||||
|
console.error('Unhandled error:', error);
|
||||||
|
res.status(500).json({ error: 'Internal server error' });
|
||||||
|
});
|
||||||
|
|
||||||
|
// 404 handler
|
||||||
|
app.use('*', (req, res) => {
|
||||||
|
res.status(404).json({ error: 'Endpoint not found' });
|
||||||
|
});
|
||||||
|
|
||||||
|
app.listen(PORT, () => {
|
||||||
|
console.log(`ScriptShare API server running on port ${PORT}`);
|
||||||
|
console.log(`Environment: ${process.env.NODE_ENV}`);
|
||||||
|
console.log(`Database URL configured: ${!!process.env.DATABASE_URL}`);
|
||||||
|
});
|
Reference in New Issue
Block a user