Enable containerization for simplified deployment and scaling of the app
Adds Dockerfile, docker-compose files, and deployment scripts for containerizing the React/Express app. Replit-Commit-Author: Agent Replit-Commit-Session-Id: 3a22ac80-cd1d-4441-9e36-f24fc2f4c3de Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/3478f7c3-db8c-4fca-9165-3adbdf1b5829/e8da43e7-d99c-4328-9fdc-485bdeecffc1.jpg
This commit is contained in:
@@ -0,0 +1,20 @@
|
|||||||
|
node_modules
|
||||||
|
npm-debug.log
|
||||||
|
.git
|
||||||
|
.gitignore
|
||||||
|
README.md
|
||||||
|
.env
|
||||||
|
.env.local
|
||||||
|
.env.production.local
|
||||||
|
.env.development.local
|
||||||
|
.env.test.local
|
||||||
|
dist
|
||||||
|
coverage
|
||||||
|
.nyc_output
|
||||||
|
.vscode
|
||||||
|
.idea
|
||||||
|
*.log
|
||||||
|
*.tgz
|
||||||
|
*.tar.gz
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
# Database Configuration
|
||||||
|
DATABASE_URL=postgresql://username:password@localhost:5432/dj_management
|
||||||
|
|
||||||
|
# Authentication
|
||||||
|
SESSION_SECRET=your-super-secret-session-key-here-minimum-32-characters-long
|
||||||
|
REPLIT_DOMAINS=localhost,yourdomain.com
|
||||||
|
REPL_ID=your-repl-id
|
||||||
|
ISSUER_URL=https://replit.com/oidc
|
||||||
|
|
||||||
|
# Application
|
||||||
|
NODE_ENV=development
|
||||||
|
PORT=5000
|
||||||
|
|
||||||
|
# PostgreSQL Database (for Docker)
|
||||||
|
PGHOST=localhost
|
||||||
|
PGPORT=5432
|
||||||
|
PGUSER=postgres
|
||||||
|
PGPASSWORD=postgres
|
||||||
|
PGDATABASE=dj_management
|
||||||
+62
@@ -0,0 +1,62 @@
|
|||||||
|
# Multi-stage build for optimized production image
|
||||||
|
FROM node:18-alpine AS builder
|
||||||
|
|
||||||
|
# Set working directory
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Copy package files
|
||||||
|
COPY package*.json ./
|
||||||
|
|
||||||
|
# Install all dependencies (including devDependencies for build)
|
||||||
|
RUN npm ci
|
||||||
|
|
||||||
|
# Copy source code
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
# Build the application
|
||||||
|
RUN npm run build
|
||||||
|
|
||||||
|
# Production stage
|
||||||
|
FROM node:18-alpine AS production
|
||||||
|
|
||||||
|
# Install dumb-init for proper signal handling
|
||||||
|
RUN apk add --no-cache dumb-init
|
||||||
|
|
||||||
|
# Create non-root user
|
||||||
|
RUN addgroup -g 1001 -S nodejs
|
||||||
|
RUN adduser -S nodejs -u 1001
|
||||||
|
|
||||||
|
# Set working directory
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Copy package files
|
||||||
|
COPY package*.json ./
|
||||||
|
|
||||||
|
# Install only production dependencies
|
||||||
|
RUN npm ci --only=production && npm cache clean --force
|
||||||
|
|
||||||
|
# Copy built application from builder stage
|
||||||
|
COPY --from=builder /app/dist ./dist
|
||||||
|
COPY --from=builder /app/dist/public ./dist/public
|
||||||
|
|
||||||
|
# Create uploads directory for file uploads
|
||||||
|
RUN mkdir -p uploads && chown nodejs:nodejs uploads
|
||||||
|
|
||||||
|
# Change ownership of app directory
|
||||||
|
RUN chown -R nodejs:nodejs /app
|
||||||
|
|
||||||
|
# Switch to non-root user
|
||||||
|
USER nodejs
|
||||||
|
|
||||||
|
# Expose port
|
||||||
|
EXPOSE 5000
|
||||||
|
|
||||||
|
# Set environment variables
|
||||||
|
ENV NODE_ENV=production
|
||||||
|
|
||||||
|
# Health check
|
||||||
|
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
|
||||||
|
CMD node -e "const http = require('http'); const options = { host: 'localhost', port: 5000, path: '/', timeout: 2000 }; const req = http.request(options, (res) => { process.exit(res.statusCode === 200 ? 0 : 1); }); req.on('error', () => process.exit(1)); req.end();"
|
||||||
|
|
||||||
|
# Start the application with dumb-init
|
||||||
|
CMD ["dumb-init", "npm", "start"]
|
||||||
@@ -0,0 +1,159 @@
|
|||||||
|
# DJ Management System
|
||||||
|
|
||||||
|
A comprehensive web-based DJ management and event scheduling system built with React, Express.js, and PostgreSQL.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- **User Management**: DJ profiles with social media links, bio, and contact information
|
||||||
|
- **Event Management**: Create, schedule, and manage DJ events with multiple event types
|
||||||
|
- **Availability System**: Calendar-based availability management for DJs
|
||||||
|
- **Admin Dashboard**: Complete administrative controls for user and event management
|
||||||
|
- **Assignment Tool**: Automated DJ assignment with rotation algorithms
|
||||||
|
- **WordPress Integration**: API endpoints for displaying events on WordPress sites
|
||||||
|
- **Authentication**: Secure authentication using Replit Auth (OpenID Connect)
|
||||||
|
|
||||||
|
## Quick Start with Docker
|
||||||
|
|
||||||
|
### Prerequisites
|
||||||
|
- Docker and Docker Compose installed on your system
|
||||||
|
|
||||||
|
### Environment Setup
|
||||||
|
|
||||||
|
1. Create a `.env` file in the root directory:
|
||||||
|
```bash
|
||||||
|
# Database Configuration
|
||||||
|
DATABASE_URL=postgresql://postgres:postgres@db:5432/dj_management
|
||||||
|
|
||||||
|
# Authentication
|
||||||
|
SESSION_SECRET=your-super-secret-session-key-here-minimum-32-chars
|
||||||
|
REPLIT_DOMAINS=localhost,yourdomain.com
|
||||||
|
REPL_ID=your-repl-id
|
||||||
|
ISSUER_URL=https://replit.com/oidc
|
||||||
|
|
||||||
|
# Application
|
||||||
|
NODE_ENV=production
|
||||||
|
PORT=5000
|
||||||
|
```
|
||||||
|
|
||||||
|
### Running with Docker Compose
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Build and start the application
|
||||||
|
docker-compose up --build
|
||||||
|
|
||||||
|
# Run in detached mode
|
||||||
|
docker-compose up -d --build
|
||||||
|
|
||||||
|
# Stop the application
|
||||||
|
docker-compose down
|
||||||
|
|
||||||
|
# View logs
|
||||||
|
docker-compose logs -f app
|
||||||
|
```
|
||||||
|
|
||||||
|
The application will be available at `http://localhost:5000`
|
||||||
|
|
||||||
|
### Building Docker Image Manually
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Build the Docker image
|
||||||
|
docker build -t dj-management .
|
||||||
|
|
||||||
|
# Run the container
|
||||||
|
docker run -p 5000:5000 \
|
||||||
|
-e DATABASE_URL="your-database-url" \
|
||||||
|
-e SESSION_SECRET="your-session-secret" \
|
||||||
|
-e REPLIT_DOMAINS="localhost" \
|
||||||
|
dj-management
|
||||||
|
```
|
||||||
|
|
||||||
|
## Development Setup
|
||||||
|
|
||||||
|
### Prerequisites
|
||||||
|
- Node.js 18+
|
||||||
|
- PostgreSQL database
|
||||||
|
- npm or yarn
|
||||||
|
|
||||||
|
### Local Development
|
||||||
|
|
||||||
|
1. Install dependencies:
|
||||||
|
```bash
|
||||||
|
npm install
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Set up environment variables:
|
||||||
|
```bash
|
||||||
|
cp .env.example .env
|
||||||
|
# Edit .env with your configuration
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Set up the database:
|
||||||
|
```bash
|
||||||
|
npm run db:push
|
||||||
|
```
|
||||||
|
|
||||||
|
4. Start the development server:
|
||||||
|
```bash
|
||||||
|
npm run dev
|
||||||
|
```
|
||||||
|
|
||||||
|
## API Endpoints
|
||||||
|
|
||||||
|
### Authentication
|
||||||
|
- `GET /api/login` - Initiate login flow
|
||||||
|
- `GET /api/logout` - Logout user
|
||||||
|
- `GET /api/auth/user` - Get current user
|
||||||
|
|
||||||
|
### Events
|
||||||
|
- `GET /api/events` - Get all events
|
||||||
|
- `POST /api/events` - Create new event
|
||||||
|
- `GET /api/events/upcoming` - Get upcoming events
|
||||||
|
- `GET /api/events/public` - Public events (for WordPress integration)
|
||||||
|
|
||||||
|
### Admin
|
||||||
|
- `GET /api/users` - Get all users (admin only)
|
||||||
|
- `GET /api/stats/admin` - Admin dashboard statistics
|
||||||
|
- `POST /api/invitations` - Send DJ invitation
|
||||||
|
|
||||||
|
## WordPress Integration
|
||||||
|
|
||||||
|
The system provides public API endpoints for WordPress integration:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// Fetch upcoming events for WordPress widget
|
||||||
|
fetch('https://your-domain.com/api/events/public')
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(events => {
|
||||||
|
// Display events in WordPress
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
## Production Deployment
|
||||||
|
|
||||||
|
### Docker Deployment
|
||||||
|
|
||||||
|
1. Update the `docker-compose.yml` with your production settings
|
||||||
|
2. Set up proper SSL/TLS certificates
|
||||||
|
3. Configure your reverse proxy (nginx/Apache)
|
||||||
|
4. Set up proper backup for PostgreSQL data
|
||||||
|
|
||||||
|
### Environment Variables
|
||||||
|
|
||||||
|
Required environment variables for production:
|
||||||
|
- `DATABASE_URL`: PostgreSQL connection string
|
||||||
|
- `SESSION_SECRET`: Secure session encryption key
|
||||||
|
- `REPLIT_DOMAINS`: Comma-separated list of allowed domains
|
||||||
|
- `REPL_ID`: Your Replit application ID
|
||||||
|
- `NODE_ENV`: Set to "production"
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
- **Frontend**: React 18 with TypeScript, Vite, TailwindCSS
|
||||||
|
- **Backend**: Express.js with TypeScript, Drizzle ORM
|
||||||
|
- **Database**: PostgreSQL with session storage
|
||||||
|
- **Authentication**: OpenID Connect (Replit Auth)
|
||||||
|
- **UI Components**: Radix UI primitives with shadcn/ui
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
MIT License - see LICENSE file for details
|
||||||
@@ -0,0 +1,164 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# DJ Management System Deployment Script
|
||||||
|
# This script helps deploy the application using Docker
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Colors for output
|
||||||
|
RED='\033[0;31m'
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
NC='\033[0m' # No Color
|
||||||
|
|
||||||
|
echo -e "${GREEN}🎵 DJ Management System Deployment Script${NC}"
|
||||||
|
echo "================================================="
|
||||||
|
|
||||||
|
# Check if Docker is installed
|
||||||
|
if ! command -v docker &> /dev/null; then
|
||||||
|
echo -e "${RED}❌ Docker is not installed. Please install Docker first.${NC}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check if Docker Compose is installed
|
||||||
|
if ! command -v docker-compose &> /dev/null; then
|
||||||
|
echo -e "${RED}❌ Docker Compose is not installed. Please install Docker Compose first.${NC}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Function to create .env file if it doesn't exist
|
||||||
|
create_env_file() {
|
||||||
|
if [ ! -f .env ]; then
|
||||||
|
echo -e "${YELLOW}📝 Creating .env file from template...${NC}"
|
||||||
|
cp .env.example .env
|
||||||
|
echo -e "${YELLOW}⚠️ Please edit .env file with your configuration before proceeding.${NC}"
|
||||||
|
read -p "Press Enter to continue after editing .env file..."
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to generate a random session secret
|
||||||
|
generate_session_secret() {
|
||||||
|
if [ -f .env ]; then
|
||||||
|
if grep -q "your-super-secret-session-key" .env; then
|
||||||
|
echo -e "${YELLOW}🔐 Generating secure session secret...${NC}"
|
||||||
|
SESSION_SECRET=$(openssl rand -base64 32)
|
||||||
|
sed -i "s/your-super-secret-session-key-here-minimum-32-characters-long/$SESSION_SECRET/" .env
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to build and start the application
|
||||||
|
deploy_application() {
|
||||||
|
echo -e "${GREEN}🚀 Building and starting the DJ Management System...${NC}"
|
||||||
|
|
||||||
|
# Build the Docker image
|
||||||
|
docker-compose build --no-cache
|
||||||
|
|
||||||
|
# Start the services
|
||||||
|
docker-compose up -d
|
||||||
|
|
||||||
|
# Wait for services to be ready
|
||||||
|
echo -e "${YELLOW}⏳ Waiting for services to start...${NC}"
|
||||||
|
sleep 10
|
||||||
|
|
||||||
|
# Check if services are running
|
||||||
|
if docker-compose ps | grep -q "Up"; then
|
||||||
|
echo -e "${GREEN}✅ DJ Management System is running!${NC}"
|
||||||
|
echo ""
|
||||||
|
echo "🌐 Application URL: http://localhost:5000"
|
||||||
|
echo "📊 Database: PostgreSQL on port 5432"
|
||||||
|
echo ""
|
||||||
|
echo "📋 To view logs: docker-compose logs -f"
|
||||||
|
echo "🛑 To stop: docker-compose down"
|
||||||
|
echo "🔄 To restart: docker-compose restart"
|
||||||
|
else
|
||||||
|
echo -e "${RED}❌ Failed to start services. Check logs with: docker-compose logs${NC}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to deploy production version
|
||||||
|
deploy_production() {
|
||||||
|
echo -e "${GREEN}🏭 Deploying production version...${NC}"
|
||||||
|
|
||||||
|
# Use production docker-compose file
|
||||||
|
docker-compose -f docker-compose.prod.yml build --no-cache
|
||||||
|
docker-compose -f docker-compose.prod.yml up -d
|
||||||
|
|
||||||
|
echo -e "${GREEN}✅ Production deployment complete!${NC}"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to show usage
|
||||||
|
show_usage() {
|
||||||
|
echo "Usage: $0 [OPTION]"
|
||||||
|
echo "Options:"
|
||||||
|
echo " dev Deploy development version (default)"
|
||||||
|
echo " prod Deploy production version"
|
||||||
|
echo " stop Stop all services"
|
||||||
|
echo " restart Restart all services"
|
||||||
|
echo " logs Show application logs"
|
||||||
|
echo " clean Clean up Docker containers and images"
|
||||||
|
echo " help Show this help message"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to stop services
|
||||||
|
stop_services() {
|
||||||
|
echo -e "${YELLOW}🛑 Stopping DJ Management System...${NC}"
|
||||||
|
docker-compose down
|
||||||
|
echo -e "${GREEN}✅ Services stopped.${NC}"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to restart services
|
||||||
|
restart_services() {
|
||||||
|
echo -e "${YELLOW}🔄 Restarting DJ Management System...${NC}"
|
||||||
|
docker-compose restart
|
||||||
|
echo -e "${GREEN}✅ Services restarted.${NC}"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to show logs
|
||||||
|
show_logs() {
|
||||||
|
echo -e "${GREEN}📋 Showing application logs...${NC}"
|
||||||
|
docker-compose logs -f app
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to clean up Docker resources
|
||||||
|
clean_up() {
|
||||||
|
echo -e "${YELLOW}🧹 Cleaning up Docker resources...${NC}"
|
||||||
|
docker-compose down --volumes --remove-orphans
|
||||||
|
docker system prune -f
|
||||||
|
echo -e "${GREEN}✅ Cleanup complete.${NC}"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Main script logic
|
||||||
|
case "${1:-dev}" in
|
||||||
|
dev)
|
||||||
|
create_env_file
|
||||||
|
generate_session_secret
|
||||||
|
deploy_application
|
||||||
|
;;
|
||||||
|
prod)
|
||||||
|
create_env_file
|
||||||
|
generate_session_secret
|
||||||
|
deploy_production
|
||||||
|
;;
|
||||||
|
stop)
|
||||||
|
stop_services
|
||||||
|
;;
|
||||||
|
restart)
|
||||||
|
restart_services
|
||||||
|
;;
|
||||||
|
logs)
|
||||||
|
show_logs
|
||||||
|
;;
|
||||||
|
clean)
|
||||||
|
clean_up
|
||||||
|
;;
|
||||||
|
help)
|
||||||
|
show_usage
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo -e "${RED}❌ Invalid option: $1${NC}"
|
||||||
|
show_usage
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
version: '3.8'
|
||||||
|
|
||||||
|
services:
|
||||||
|
app:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
target: production
|
||||||
|
ports:
|
||||||
|
- "5000:5000"
|
||||||
|
environment:
|
||||||
|
- NODE_ENV=production
|
||||||
|
- DATABASE_URL=${DATABASE_URL}
|
||||||
|
- SESSION_SECRET=${SESSION_SECRET}
|
||||||
|
- REPLIT_DOMAINS=${REPLIT_DOMAINS}
|
||||||
|
- REPL_ID=${REPL_ID}
|
||||||
|
- ISSUER_URL=${ISSUER_URL:-https://replit.com/oidc}
|
||||||
|
depends_on:
|
||||||
|
db:
|
||||||
|
condition: service_healthy
|
||||||
|
volumes:
|
||||||
|
- uploads_data:/app/uploads
|
||||||
|
restart: unless-stopped
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:5000/"]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 10s
|
||||||
|
retries: 3
|
||||||
|
start_period: 40s
|
||||||
|
|
||||||
|
db:
|
||||||
|
image: postgres:15-alpine
|
||||||
|
environment:
|
||||||
|
- POSTGRES_DB=${PGDATABASE:-dj_management}
|
||||||
|
- POSTGRES_USER=${PGUSER:-postgres}
|
||||||
|
- POSTGRES_PASSWORD=${PGPASSWORD}
|
||||||
|
ports:
|
||||||
|
- "5432:5432"
|
||||||
|
volumes:
|
||||||
|
- postgres_data:/var/lib/postgresql/data
|
||||||
|
- ./init.sql:/docker-entrypoint-initdb.d/init.sql
|
||||||
|
restart: unless-stopped
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "pg_isready -U ${PGUSER:-postgres} -d ${PGDATABASE:-dj_management}"]
|
||||||
|
interval: 10s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 5
|
||||||
|
|
||||||
|
# Optional: Redis for session storage (alternative to PostgreSQL sessions)
|
||||||
|
redis:
|
||||||
|
image: redis:7-alpine
|
||||||
|
ports:
|
||||||
|
- "6379:6379"
|
||||||
|
volumes:
|
||||||
|
- redis_data:/data
|
||||||
|
restart: unless-stopped
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "redis-cli", "ping"]
|
||||||
|
interval: 10s
|
||||||
|
timeout: 3s
|
||||||
|
retries: 5
|
||||||
|
|
||||||
|
# Optional: Nginx reverse proxy
|
||||||
|
nginx:
|
||||||
|
image: nginx:alpine
|
||||||
|
ports:
|
||||||
|
- "80:80"
|
||||||
|
- "443:443"
|
||||||
|
volumes:
|
||||||
|
- ./nginx.conf:/etc/nginx/nginx.conf
|
||||||
|
- ./ssl:/etc/nginx/ssl
|
||||||
|
depends_on:
|
||||||
|
- app
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
postgres_data:
|
||||||
|
redis_data:
|
||||||
|
uploads_data:
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
version: '3.8'
|
||||||
|
|
||||||
|
services:
|
||||||
|
app:
|
||||||
|
build: .
|
||||||
|
ports:
|
||||||
|
- "5000:5000"
|
||||||
|
environment:
|
||||||
|
- NODE_ENV=production
|
||||||
|
- DATABASE_URL=postgresql://postgres:postgres@db:5432/dj_management
|
||||||
|
- SESSION_SECRET=your-super-secret-session-key-here
|
||||||
|
- REPLIT_DOMAINS=localhost
|
||||||
|
- REPL_ID=your-repl-id
|
||||||
|
- ISSUER_URL=https://replit.com/oidc
|
||||||
|
depends_on:
|
||||||
|
- db
|
||||||
|
volumes:
|
||||||
|
- ./uploads:/app/uploads
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
db:
|
||||||
|
image: postgres:15-alpine
|
||||||
|
environment:
|
||||||
|
- POSTGRES_DB=dj_management
|
||||||
|
- POSTGRES_USER=postgres
|
||||||
|
- POSTGRES_PASSWORD=postgres
|
||||||
|
ports:
|
||||||
|
- "5432:5432"
|
||||||
|
volumes:
|
||||||
|
- postgres_data:/var/lib/postgresql/data
|
||||||
|
- ./init.sql:/docker-entrypoint-initdb.d/init.sql
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
postgres_data:
|
||||||
@@ -0,0 +1,143 @@
|
|||||||
|
-- Database initialization script for Docker container
|
||||||
|
-- This script sets up the initial database schema
|
||||||
|
|
||||||
|
-- Create sessions table for auth
|
||||||
|
CREATE TABLE IF NOT EXISTS sessions (
|
||||||
|
sid VARCHAR PRIMARY KEY,
|
||||||
|
sess JSONB NOT NULL,
|
||||||
|
expire TIMESTAMP NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Create index for sessions
|
||||||
|
CREATE INDEX IF NOT EXISTS IDX_session_expire ON sessions(expire);
|
||||||
|
|
||||||
|
-- Create enum for user roles
|
||||||
|
CREATE TYPE user_role AS ENUM ('dj', 'admin');
|
||||||
|
|
||||||
|
-- Create users table
|
||||||
|
CREATE TABLE IF NOT EXISTS users (
|
||||||
|
id VARCHAR PRIMARY KEY,
|
||||||
|
email VARCHAR UNIQUE,
|
||||||
|
first_name VARCHAR,
|
||||||
|
last_name VARCHAR,
|
||||||
|
profile_image_url VARCHAR,
|
||||||
|
display_name VARCHAR,
|
||||||
|
bio TEXT,
|
||||||
|
phone VARCHAR,
|
||||||
|
location VARCHAR,
|
||||||
|
website VARCHAR,
|
||||||
|
role user_role DEFAULT 'dj',
|
||||||
|
is_active BOOLEAN DEFAULT true,
|
||||||
|
max_monthly_events INTEGER DEFAULT 4,
|
||||||
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Create event types table
|
||||||
|
CREATE TABLE IF NOT EXISTS event_types (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
name VARCHAR NOT NULL,
|
||||||
|
description TEXT,
|
||||||
|
color VARCHAR DEFAULT '#3B82F6',
|
||||||
|
is_active BOOLEAN DEFAULT true,
|
||||||
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Create schedule templates table
|
||||||
|
CREATE TABLE IF NOT EXISTS schedule_templates (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
name VARCHAR NOT NULL,
|
||||||
|
description TEXT,
|
||||||
|
is_active BOOLEAN DEFAULT true,
|
||||||
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Create schedule template slots table
|
||||||
|
CREATE TABLE IF NOT EXISTS schedule_template_slots (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
template_id INTEGER REFERENCES schedule_templates(id) ON DELETE CASCADE,
|
||||||
|
day_of_week INTEGER NOT NULL CHECK (day_of_week >= 0 AND day_of_week <= 6),
|
||||||
|
start_time TIME NOT NULL,
|
||||||
|
end_time TIME NOT NULL,
|
||||||
|
event_type_id INTEGER REFERENCES event_types(id),
|
||||||
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Create events table
|
||||||
|
CREATE TABLE IF NOT EXISTS events (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
title VARCHAR NOT NULL,
|
||||||
|
description TEXT,
|
||||||
|
date DATE NOT NULL,
|
||||||
|
start_time TIME NOT NULL,
|
||||||
|
end_time TIME NOT NULL,
|
||||||
|
location VARCHAR,
|
||||||
|
event_type_id INTEGER REFERENCES event_types(id),
|
||||||
|
dj_id VARCHAR REFERENCES users(id),
|
||||||
|
is_admin_assigned BOOLEAN DEFAULT false,
|
||||||
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Create social links table
|
||||||
|
CREATE TABLE IF NOT EXISTS social_links (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
dj_id VARCHAR REFERENCES users(id) ON DELETE CASCADE,
|
||||||
|
platform VARCHAR NOT NULL,
|
||||||
|
url VARCHAR NOT NULL,
|
||||||
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Create availability table
|
||||||
|
CREATE TABLE IF NOT EXISTS availability (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
dj_id VARCHAR REFERENCES users(id) ON DELETE CASCADE,
|
||||||
|
date DATE NOT NULL,
|
||||||
|
is_available BOOLEAN DEFAULT true,
|
||||||
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
UNIQUE(dj_id, date)
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Create slot eligibility table
|
||||||
|
CREATE TABLE IF NOT EXISTS slot_eligibility (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
dj_id VARCHAR REFERENCES users(id) ON DELETE CASCADE,
|
||||||
|
event_type_id INTEGER REFERENCES event_types(id),
|
||||||
|
is_eligible BOOLEAN DEFAULT true,
|
||||||
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Create removal requests table
|
||||||
|
CREATE TABLE IF NOT EXISTS removal_requests (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
event_id INTEGER REFERENCES events(id) ON DELETE CASCADE,
|
||||||
|
dj_id VARCHAR REFERENCES users(id),
|
||||||
|
reason TEXT NOT NULL,
|
||||||
|
status VARCHAR DEFAULT 'pending' CHECK (status IN ('pending', 'approved', 'denied')),
|
||||||
|
reviewed_by VARCHAR REFERENCES users(id),
|
||||||
|
reviewed_at TIMESTAMP,
|
||||||
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Create invitations table
|
||||||
|
CREATE TABLE IF NOT EXISTS invitations (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
email VARCHAR NOT NULL,
|
||||||
|
token VARCHAR UNIQUE NOT NULL,
|
||||||
|
expires_at TIMESTAMP NOT NULL,
|
||||||
|
is_used BOOLEAN DEFAULT false,
|
||||||
|
created_by VARCHAR REFERENCES users(id),
|
||||||
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Insert some default event types
|
||||||
|
INSERT INTO event_types (name, description, color) VALUES
|
||||||
|
('Radio Show', 'Regular radio broadcasting', '#3B82F6'),
|
||||||
|
('Club Night', 'Club and nightclub events', '#10B981'),
|
||||||
|
('Wedding', 'Wedding and celebration events', '#F59E0B'),
|
||||||
|
('Corporate Event', 'Business and corporate functions', '#6366F1'),
|
||||||
|
('Festival', 'Music festivals and outdoor events', '#EF4444'),
|
||||||
|
('Special Event', 'Special occasions and one-time events', '#8B5CF6')
|
||||||
|
ON CONFLICT DO NOTHING;
|
||||||
+116
@@ -0,0 +1,116 @@
|
|||||||
|
events {
|
||||||
|
worker_connections 1024;
|
||||||
|
}
|
||||||
|
|
||||||
|
http {
|
||||||
|
include /etc/nginx/mime.types;
|
||||||
|
default_type application/octet-stream;
|
||||||
|
|
||||||
|
# Logging
|
||||||
|
access_log /var/log/nginx/access.log;
|
||||||
|
error_log /var/log/nginx/error.log;
|
||||||
|
|
||||||
|
# Gzip compression
|
||||||
|
gzip on;
|
||||||
|
gzip_vary on;
|
||||||
|
gzip_min_length 1024;
|
||||||
|
gzip_proxied any;
|
||||||
|
gzip_comp_level 6;
|
||||||
|
gzip_types
|
||||||
|
text/plain
|
||||||
|
text/css
|
||||||
|
text/xml
|
||||||
|
text/javascript
|
||||||
|
application/json
|
||||||
|
application/javascript
|
||||||
|
application/xml+rss
|
||||||
|
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;
|
||||||
|
|
||||||
|
# Upstream for the Node.js app
|
||||||
|
upstream app {
|
||||||
|
server app:5000;
|
||||||
|
}
|
||||||
|
|
||||||
|
# HTTP server (redirect to HTTPS)
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
server_name _;
|
||||||
|
return 301 https://$server_name$request_uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
# HTTPS server
|
||||||
|
server {
|
||||||
|
listen 443 ssl http2;
|
||||||
|
server_name _;
|
||||||
|
|
||||||
|
# SSL configuration
|
||||||
|
ssl_certificate /etc/nginx/ssl/cert.pem;
|
||||||
|
ssl_certificate_key /etc/nginx/ssl/key.pem;
|
||||||
|
ssl_protocols TLSv1.2 TLSv1.3;
|
||||||
|
ssl_ciphers HIGH:!aNULL:!MD5;
|
||||||
|
ssl_prefer_server_ciphers on;
|
||||||
|
|
||||||
|
# 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 Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
|
||||||
|
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:;" always;
|
||||||
|
|
||||||
|
# Client max body size for file uploads
|
||||||
|
client_max_body_size 10M;
|
||||||
|
|
||||||
|
# Rate limiting for API endpoints
|
||||||
|
location /api/ {
|
||||||
|
limit_req zone=api burst=20 nodelay;
|
||||||
|
proxy_pass http://app;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection 'upgrade';
|
||||||
|
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_cache_bypass $http_upgrade;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Rate limiting for login endpoints
|
||||||
|
location /api/login {
|
||||||
|
limit_req zone=login burst=5 nodelay;
|
||||||
|
proxy_pass http://app;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection 'upgrade';
|
||||||
|
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_cache_bypass $http_upgrade;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Static files with caching
|
||||||
|
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
|
||||||
|
expires 1y;
|
||||||
|
add_header Cache-Control "public, immutable";
|
||||||
|
proxy_pass http://app;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Default location
|
||||||
|
location / {
|
||||||
|
proxy_pass http://app;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection 'upgrade';
|
||||||
|
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_cache_bypass $http_upgrade;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -114,17 +114,28 @@ Preferred communication style: Simple, everyday language.
|
|||||||
- **Database**: Drizzle migrations manage schema changes
|
- **Database**: Drizzle migrations manage schema changes
|
||||||
- **Environment**: Supports both development and production modes
|
- **Environment**: Supports both development and production modes
|
||||||
|
|
||||||
|
### Docker Containerization
|
||||||
|
- **Multi-stage Build**: Optimized Docker image with builder and production stages
|
||||||
|
- **Security**: Non-root user, proper signal handling with dumb-init
|
||||||
|
- **Health Checks**: Built-in health monitoring for container orchestration
|
||||||
|
- **Development**: `docker-compose.yml` for local development with PostgreSQL
|
||||||
|
- **Production**: `docker-compose.prod.yml` with Redis, Nginx, and SSL support
|
||||||
|
- **Deployment Script**: `deploy.sh` for automated deployment management
|
||||||
|
|
||||||
### Environment Configuration
|
### Environment Configuration
|
||||||
- **DATABASE_URL**: PostgreSQL connection string (required)
|
- **DATABASE_URL**: PostgreSQL connection string (required)
|
||||||
- **SESSION_SECRET**: Session encryption key
|
- **SESSION_SECRET**: Session encryption key
|
||||||
- **REPLIT_DOMAINS**: Allowed domains for Replit Auth
|
- **REPLIT_DOMAINS**: Allowed domains for Replit Auth
|
||||||
- **NODE_ENV**: Environment mode (development/production)
|
- **NODE_ENV**: Environment mode (development/production)
|
||||||
|
- **REPL_ID**: Replit application identifier for authentication
|
||||||
|
|
||||||
### Hosting Requirements
|
### Hosting Requirements
|
||||||
- **Node.js**: Version 18+ with ES modules support
|
- **Node.js**: Version 18+ with ES modules support
|
||||||
- **PostgreSQL**: Compatible with Neon serverless or traditional PostgreSQL
|
- **PostgreSQL**: Compatible with Neon serverless or traditional PostgreSQL
|
||||||
- **SSL/TLS**: Required for secure authentication flows
|
- **SSL/TLS**: Required for secure authentication flows
|
||||||
- **File Storage**: Local storage for uploaded profile images (can be extended to cloud storage)
|
- **File Storage**: Local storage for uploaded profile images (can be extended to cloud storage)
|
||||||
|
- **Docker**: Container runtime for production deployment
|
||||||
|
- **Nginx**: Optional reverse proxy for production (included in Docker setup)
|
||||||
|
|
||||||
### Database Architecture
|
### Database Architecture
|
||||||
- **Schema Management**: Drizzle ORM with TypeScript schema definitions
|
- **Schema Management**: Drizzle ORM with TypeScript schema definitions
|
||||||
|
|||||||
Reference in New Issue
Block a user