production configs, deployment configs and readme

This commit is contained in:
mikicvi
2025-09-28 13:35:08 +01:00
parent b95a2ab2e4
commit 429eebb68f
15 changed files with 1115 additions and 44 deletions
+11
View File
@@ -0,0 +1,11 @@
# Docker ignore file
node_modules
.next
.git
.env.local
.env.development
*.log
npm-debug.log*
.DS_Store
*.tgz
*.tar.gz
+28
View File
@@ -0,0 +1,28 @@
# Production Environment Configuration
# Domain: lcc-tt-booking.mikicvi.com
# Database
DATABASE_URL="./data/sqlite.db"
# NextAuth.js
NEXTAUTH_URL="https://lcc-tt-booking.mikicvi.com"
NEXTAUTH_SECRET="qHYNaq516ByAY6H4HdxacMICd05I1DqvrTitIuVtT20="
# Email Configuration (Gmail - Update with your credentials)
EMAIL_USER="your-email@gmail.com"
EMAIL_PASSWORD="your-app-password-here"
# Admin Configuration (Change these for production!)
ADMIN_EMAIL="admin@lcc-tt-booking.mikicvi.com"
ADMIN_PASSWORD="ChangeMeInProduction123!"
# Application Settings
NODE_ENV="production"
PORT="3000"
# Rate Limiting
RATE_LIMIT_MAX="100"
RATE_LIMIT_WINDOW="900000"
# Logging
LOG_LEVEL="info"
+506
View File
@@ -0,0 +1,506 @@
# Deployment Strategy for Table Tennis Booking System
## Overview
This document outlines comprehensive deployment strategies for the Table Tennis Booking System, considering both self-hosting and cloud deployment options. The application is a Next.js-based system with SQLite database, designed for production use.
## 1. Self-Hosting Strategy
### Option A: Raspberry Pi + Cloudflare Tunnel (Recommended)
**Architecture:**
```
Internet → Cloudflare → Cloudflare Tunnel → Raspberry Pi → Docker Container
```
**Requirements:**
- Raspberry Pi 4 (4GB+ RAM recommended)
- Stable internet connection
- Cloudflare account (free tier sufficient)
- Domain name (can be managed through Cloudflare)
**Setup Steps:**
1. **Raspberry Pi Preparation**
```bash
# Update system
sudo apt update && sudo apt upgrade -y
# Install Docker
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
sudo usermod -aG docker $USER
# Install Docker Compose
sudo apt install docker-compose -y
```
2. **Application Deployment**
```bash
# Clone repository
git clone <your-repo-url>
cd tt-booking
# Create production environment file
cp .env.example .env.production
# Edit .env.production with your values
# Deploy with Docker
docker-compose -f docker-compose.production.yml up -d
```
3. **Cloudflare Tunnel Setup**
```bash
# Install cloudflared
wget https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-arm64.deb
sudo dpkg -i cloudflared-linux-arm64.deb
# Authenticate
cloudflared tunnel login
# Create tunnel
cloudflared tunnel create tt-booking
# Configure tunnel (create config.yml)
cloudflared tunnel route dns tt-booking yourdomain.com
# Run tunnel
cloudflared tunnel run tt-booking
```
**Cloudflare Tunnel Config (`~/.cloudflared/config.yml`):**
```yaml
tunnel: <tunnel-id>
credentials-file: /home/pi/.cloudflared/<tunnel-id>.json
ingress:
- hostname: yourdomain.com
service: http://localhost:3000
- service: http_status:404
```
**Production Docker Compose (`docker-compose.production.yml`):**
```yaml
version: '3.8'
services:
tt-booking:
build: .
ports:
- '3000:3000'
environment:
- NODE_ENV=production
- DATABASE_URL=/app/data/sqlite.db
- NEXTAUTH_URL=https://yourdomain.com
- NEXTAUTH_SECRET=${NEXTAUTH_SECRET}
- EMAIL_USER=${EMAIL_USER}
- EMAIL_PASSWORD=${EMAIL_PASSWORD}
- ADMIN_EMAIL=${ADMIN_EMAIL}
- ADMIN_PASSWORD=${ADMIN_PASSWORD}
volumes:
- ./data:/app/data
- ./backups:/app/backups
restart: unless-stopped
healthcheck:
test: ['CMD', 'curl', '-f', 'http://localhost:3000/api/health']
interval: 30s
timeout: 10s
retries: 3
# Backup service
backup:
image: alpine:latest
volumes:
- ./data:/data:ro
- ./backups:/backups
command: >
sh -c "
while true; do
cp /data/sqlite.db /backups/sqlite-$(date +%Y%m%d-%H%M%S).db
find /backups -name 'sqlite-*.db' -mtime +7 -delete
sleep 86400
done"
restart: unless-stopped
```
**Advantages:**
- No need for port forwarding or exposing home IP
- Free SSL certificates through Cloudflare
- DDoS protection and CDN benefits
- Easy domain management
- Cost-effective (only domain cost ~$10-15/year)
**Disadvantages:**
- Dependent on home internet stability
- Limited by residential bandwidth
- Requires basic Linux administration skills
### Option B: Traditional Self-Hosting with Reverse Proxy
**Architecture:**
```
Internet → Router/Firewall → Nginx → Docker Container
```
**Requirements:**
- Dedicated server or powerful Raspberry Pi
- Static IP address or Dynamic DNS service
- SSL certificate (Let's Encrypt)
- Port forwarding configuration
**Setup includes all the Docker setup above, plus:**
1. **Nginx Configuration**
```bash
# Install Nginx
sudo apt install nginx certbot python3-certbot-nginx
# Configure SSL
sudo certbot --nginx -d yourdomain.com
```
2. **Updated Docker Compose with Nginx**
Use the existing [docker-compose.yml](docker-compose.yml) with Nginx service.
**Advantages:**
- Full control over infrastructure
- No dependency on third-party tunneling services
- Better performance for local network access
**Disadvantages:**
- Requires static IP or Dynamic DNS
- More complex firewall/security configuration
- SSL certificate management overhead
## 2. Cloud Deployment Strategies
### Option A: DigitalOcean App Platform (Recommended for Small Scale)
**Cost Estimate:** $12-25/month
**Features:**
- Automatic deployments from Git
- Built-in SSL certificates
- Automatic scaling
- Integrated monitoring
**Deployment:**
1. Connect GitHub repository
2. Configure environment variables
3. Add persistent volume for SQLite database
4. Deploy with zero-config
**Configuration:**
```yaml
# .do/app.yaml
name: tt-booking
services:
- name: web
source_dir: /
github:
repo: your-username/tt-booking
branch: main
run_command: npm start
environment_slug: node-js
instance_count: 1
instance_size_slug: basic-xxs
envs:
- key: NODE_ENV
value: production
- key: DATABASE_URL
value: /app/data/sqlite.db
```
### Option B: Railway (Developer-Friendly)
**Cost Estimate:** $5-20/month
**Features:**
- Git-based deployments
- Built-in databases available
- Simple pricing model
- Excellent developer experience
**Deployment:**
```bash
# Install Railway CLI
npm install -g @railway/cli
# Login and deploy
railway login
railway init
railway up
```
### Option C: Vercel + PlanetScale (Serverless)
**Cost Estimate:** $0-20/month (depending on usage)
**Modifications needed:**
- Replace SQLite with PlanetScale MySQL
- Update database schema for MySQL compatibility
- Modify connection configuration
**Deployment:**
```bash
# Install Vercel CLI
npm install -g vercel
# Deploy
vercel --prod
```
### Option D: AWS/GCP/Azure (Enterprise Scale)
**Cost Estimate:** $30-100+/month
**AWS Deployment Options:**
1. **ECS Fargate + RDS**
- Container-based deployment
- Managed database
- Auto-scaling capabilities
2. **Elastic Beanstalk**
- Simple deployment model
- Built-in monitoring
- Easy environment management
3. **App Runner**
- Serverless container platform
- Automatic scaling
- Pay-per-use pricing
## 3. Database Considerations
### For Self-Hosting
- **SQLite**: Perfect for small to medium loads
- **Backup Strategy**: Automated daily backups to external storage
- **Monitoring**: Simple file-based health checks
### For Cloud Deployment
- **Small Scale**: Keep SQLite with persistent volumes
- **Medium Scale**: PostgreSQL (Railway, DigitalOcean Managed DB)
- **Large Scale**: Multi-region database (AWS RDS, Google Cloud SQL)
## 4. Monitoring and Maintenance
### Essential Monitoring
```bash
# Add to crontab for health checks
*/5 * * * * curl -f https://yourdomain.com/api/health || echo "App down" | mail -s "Alert" admin@example.com
```
### Backup Strategy
1. **Database Backups**: Daily automated SQLite file copies
2. **Environment Config**: Version controlled `.env` files
3. **Application Code**: Git-based source control
### Update Strategy
```bash
#!/bin/bash
# update.sh
cd /path/to/tt-booking
git pull origin main
docker-compose -f docker-compose.production.yml down
docker-compose -f docker-compose.production.yml up -d --build
```
## 5. Security Considerations
### Self-Hosting Security Checklist
- [ ] Firewall configured (only necessary ports open)
- [ ] Regular OS updates automated
- [ ] Non-root user for application
- [ ] SSL certificates properly configured
- [ ] Database backups encrypted
- [ ] Rate limiting configured (already in nginx.conf)
- [ ] Log monitoring for suspicious activity
### Cloud Security
- [ ] Environment variables properly secured
- [ ] Database access restricted
- [ ] API rate limiting enabled
- [ ] Regular dependency updates
- [ ] Security headers configured (already in app)
## 6. Cost Comparison
| Deployment Method | Monthly Cost | Effort | Scalability | Reliability |
| ------------------------- | ------------ | -------- | ----------- | ----------- |
| Raspberry Pi + CF Tunnel | $1-2 | Medium | Low | Medium |
| Traditional Self-Host | $5-10 | High | Low | Medium |
| DigitalOcean App Platform | $12-25 | Low | Medium | High |
| Railway | $5-20 | Very Low | Medium | High |
| Vercel + PlanetScale | $0-20 | Low | High | High |
| AWS/GCP/Azure | $30-100+ | High | Very High | Very High |
## 7. Recommended Approach
### For Personal/Small Group Use:
**Raspberry Pi + Cloudflare Tunnel** - Most cost-effective with good reliability
### For Small Business:
**Railway or DigitalOcean App Platform** - Balance of simplicity and reliability
### For Enterprise:
**AWS/GCP with proper CI/CD pipeline** - Maximum scalability and reliability
## 8. Local Development Best Practices
### Standalone Development
```bash
# Quick development setup
npm install
npm run dev
```
### Docker Development
```bash
# Development with Docker
docker-compose up -d
```
### Production-like Local Testing
```bash
# Test production build locally
npm run build
npm start
```
## 9. Health Check Endpoint
The application includes a health check endpoint at `/api/health` for monitoring purposes. You should create this endpoint:
```typescript
// app/api/health/route.ts
import { NextResponse } from 'next/server';
import { db } from '@/lib/db';
export async function GET() {
try {
// Basic database connectivity check
await db.select().from(settings).limit(1);
return NextResponse.json({
status: 'healthy',
timestamp: new Date().toISOString(),
uptime: process.uptime(),
});
} catch (error) {
return NextResponse.json({ status: 'unhealthy', error: 'Database connection failed' }, { status: 500 });
}
}
```
## 10. Environment Variables for Production
Create a `.env.production` file with the following required variables:
```bash
# Application
NODE_ENV=production
NEXTAUTH_URL=https://yourdomain.com
NEXTAUTH_SECRET=your-very-long-random-secret-here
# Database
DATABASE_URL=/app/data/sqlite.db
# Email Configuration (optional)
EMAIL_USER=your-email@gmail.com
EMAIL_PASSWORD=your-app-specific-password
# Admin Account
ADMIN_EMAIL=admin@yourdomain.com
ADMIN_PASSWORD=secure-admin-password
# Optional: Rate limiting
RATE_LIMIT_MAX=100
RATE_LIMIT_WINDOW=900000
```
## 11. Docker Production Optimization
Create a production-optimized `Dockerfile.production`:
```dockerfile
FROM node:18-alpine AS base
# Install dependencies only when needed
FROM base AS deps
WORKDIR /app
COPY package.json package-lock.json* ./
RUN npm ci --only=production && npm cache clean --force
# Rebuild the source code only when needed
FROM base AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm run build
# Production image, copy all the files and run next
FROM base AS runner
WORKDIR /app
ENV NODE_ENV production
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs
# Copy built application
COPY --from=builder --chown=nextjs:nodejs /app/.next ./.next
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./package.json
COPY --from=builder /app/public ./public
# Create data directory for SQLite
RUN mkdir -p /app/data && chown nextjs:nodejs /app/data
USER nextjs
EXPOSE 3000
ENV PORT 3000
ENV HOSTNAME "0.0.0.0"
CMD ["npm", "start"]
```
This deployment strategy provides multiple pathways depending on your technical expertise, budget, and scaling requirements. The Cloudflare Tunnel approach is particularly attractive for self-hosting as it eliminates many traditional networking complexities while maintaining security and reliability.
+74
View File
@@ -0,0 +1,74 @@
# Multi-stage production Dockerfile for LCC Table Tennis Booking
FROM node:22-slim AS base
# Install dependencies only when needed
FROM base AS deps
RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/*
WORKDIR /app
# Install dependencies based on the preferred package manager
COPY package.json package-lock.json* ./
RUN \
if [ -f package-lock.json ]; then npm ci --ignore-scripts; \
else echo "Lockfile not found." && exit 1; \
fi
# Rebuild the source code only when needed
FROM base AS builder
RUN apt-get update && apt-get install -y python3 make g++ && rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
# Rebuild better-sqlite3 for Alpine Linux
RUN npm rebuild better-sqlite3
# Build the application
RUN npm run build
# Production image, copy all the files and run next
FROM base AS runner
RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/*
WORKDIR /app
ENV NODE_ENV=production
ENV NEXT_TELEMETRY_DISABLED=1
# Create system user and group
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs
# Copy necessary files from builder stage
COPY --from=builder /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
# Create public directory if it doesn't exist
RUN mkdir -p public
# Create directories for data and backups
RUN mkdir -p /app/data /app/backups /app/logs && \
chown -R nextjs:nodejs /app/data /app/backups /app/logs
# Create startup script
COPY --chown=nextjs:nodejs <<EOF /app/start.sh
#!/bin/sh
set -e
echo "🚀 Starting TT Booking Production..."
echo "🌟 Starting server..."
exec node server.js
EOF
RUN chmod +x /app/start.sh
USER nextjs
EXPOSE 3000
ENV PORT=3000
ENV HOSTNAME="0.0.0.0"
# Health check
HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \
CMD curl -f http://localhost:3000/api/health || exit 1
CMD ["/app/start.sh"]
+149
View File
@@ -0,0 +1,149 @@
# LCC Table Tennis Booking - Production Setup
## Quick Start
Your production environment is configured for domain: **lcc-tt-booking.mikicvi.com**
### 1. Deploy the Application
```bash
# Make deployment script executable (if not already done)
chmod +x deploy.sh
# Deploy to production
./deploy.sh
```
### 2. Set Up Cloudflare Tunnel
```bash
# Run the tunnel setup script
./setup-tunnel.sh
# Follow the instructions provided by the script
```
## Configuration Files Created
### Environment Configuration
- **`.env.production`** - Production environment variables
- **`docker-compose.production.yml`** - Production Docker Compose configuration
- **`Dockerfile.production`** - Optimized production Docker build
### Security & Secrets
- **NEXTAUTH_SECRET**: `qHYNaq516ByAY6H4HdxacMICd05I1DqvrTitIuVtT20=` (pre-generated)
- **Domain**: `lcc-tt-booking.mikicvi.com`
- **Admin Email**: `admin@lcc-tt-booking.mikicvi.com`
### Scripts & Automation
- **`deploy.sh`** - One-command production deployment
- **`setup-tunnel.sh`** - Cloudflare Tunnel setup assistant
- **`cloudflare-tunnel-config.yml`** - Tunnel configuration template
### Health & Monitoring
- **`/api/health`** - Health check endpoint with database connectivity and memory usage
- **Automated backups** - Daily SQLite backups (30-day retention)
- **Log rotation** - Automatic log management
## Production Checklist
### Before Going Live:
- [ ] Update email credentials in `.env.production`
- [ ] Change admin password from default
- [ ] Set up Cloudflare Tunnel
- [ ] Test health check endpoint
- [ ] Verify SSL certificate is working
### After Deployment:
- [ ] Test all booking functionality
- [ ] Verify admin panel access
- [ ] Check automated backups are working
- [ ] Set up monitoring alerts (optional)
## Management Commands
```bash
# View application logs
docker-compose -f docker-compose.production.yml logs -f tt-booking
# Restart application
docker-compose -f docker-compose.production.yml restart tt-booking
# Stop all services
docker-compose -f docker-compose.production.yml down
# Update and redeploy
./deploy.sh
# Access database backup
ls -la backups/
# Check application health
curl http://localhost:3000/api/health
```
## Directory Structure
```
/Users/mikicv/Documents/tt-booking/
├── .env.production # Production environment variables
├── docker-compose.production.yml # Production Docker Compose
├── Dockerfile.production # Production Docker build
├── deploy.sh # Deployment script
├── setup-tunnel.sh # Cloudflare Tunnel setup
├── cloudflare-tunnel-config.yml # Tunnel configuration
├── data/ # SQLite database storage
├── backups/ # Automated backups
└── logs/ # Application logs
```
## Default Admin Access
- **URL**: https://lcc-tt-booking.mikicvi.com/admin
- **Email**: admin@lcc-tt-booking.mikicvi.com
- **Password**: ChangeMeInProduction123! (⚠️ CHANGE THIS!)
## Support & Troubleshooting
### Common Issues:
1. **Container won't start**: Check `docker-compose -f docker-compose.production.yml logs`
2. **Database issues**: Ensure `data/` directory permissions are correct
3. **Tunnel not working**: Verify Cloudflare DNS settings and tunnel configuration
### Health Check:
The health endpoint (`/api/health`) provides:
- Application status
- Database connectivity
- Memory usage
- Uptime information
### Backup Verification:
```bash
# List all backups
ls -la backups/
# Check latest backup size
du -h backups/sqlite-$(date +%Y%m%d)*.db | tail -1
```
## Production Features Included:
- ✅ Automated daily backups (30-day retention)
- ✅ Health monitoring endpoint
- ✅ Log rotation and management
- ✅ Multi-stage Docker optimization
- ✅ Security hardening
- ✅ Rate limiting configured
- ✅ SSL-ready with Cloudflare integration
Your LCC Table Tennis Booking System is ready for production! 🏓
+43
View File
@@ -0,0 +1,43 @@
import { NextResponse } from 'next/server';
import { db } from '@/lib/db';
import { settings } from '@/lib/db/schema';
export async function GET() {
try {
// Test database connectivity
const startTime = Date.now();
await db.select().from(settings).limit(1);
const dbLatency = Date.now() - startTime;
// Check memory usage
const memoryUsage = process.memoryUsage();
return NextResponse.json({
status: 'healthy',
timestamp: new Date().toISOString(),
uptime: Math.floor(process.uptime()),
environment: process.env.NODE_ENV,
database: {
status: 'connected',
latency: `${dbLatency}ms`,
},
memory: {
rss: `${Math.round(memoryUsage.rss / 1024 / 1024)}MB`,
heapUsed: `${Math.round(memoryUsage.heapUsed / 1024 / 1024)}MB`,
heapTotal: `${Math.round(memoryUsage.heapTotal / 1024 / 1024)}MB`,
},
version: process.env.npm_package_version || '1.0.0',
});
} catch (error) {
console.error('Health check failed:', error);
return NextResponse.json(
{
status: 'unhealthy',
timestamp: new Date().toISOString(),
error: 'Database connection failed',
details: error instanceof Error ? error.message : 'Unknown error',
},
{ status: 500 }
);
}
}
+40
View File
@@ -0,0 +1,40 @@
# Cloudflare Tunnel Configuration for LCC Table Tennis Booking
# Domain: lcc-tt-booking.mikicvi.com
# Save this as ~/.cloudflared/config.yml after setting up your tunnel
tunnel: <your-tunnel-id>
credentials-file: /home/pi/.cloudflared/<your-tunnel-id>.json
# Ingress rules
ingress:
# Main application
- hostname: lcc-tt-booking.mikicvi.com
service: http://localhost:3000
originRequest:
# Enable HTTP/2
httpHostHeader: lcc-tt-booking.mikicvi.com
# Connection settings
connectTimeout: 30s
tlsTimeout: 10s
# Health checks
proxyType: http
# Disable chunked encoding for better compatibility
disableChunkedEncoding: true
# Health check endpoint (optional, for monitoring)
- hostname: health.lcc-tt-booking.mikicvi.com
service: http://localhost:3000/api/health
# Catch-all rule (must be last)
- service: http_status:404
# Optional: Logging configuration
loglevel: info
transport-loglevel: warn
# Optional: Metrics
metrics: 0.0.0.0:2000
# Optional: Enable compression
compression: gzip
Executable
+90
View File
@@ -0,0 +1,90 @@
#!/bin/bash
# LCC Table Tennis Booking - Production Deployment Script
# Domain: lcc-tt-booking.mikicvi.com
set -e
echo "🚀 Starting production deployment for LCC Table Tennis Booking..."
# Check if .env.production exists
if [ ! -f .env.production ]; then
echo "❌ .env.production file not found!"
echo "Please create .env.production with your production environment variables."
exit 1
fi
# Create necessary directories
echo "📁 Creating necessary directories..."
mkdir -p data backups logs
# Set proper permissions
echo "🔒 Setting directory permissions..."
chmod 755 data backups logs
# Pull latest changes (if using git)
if [ -d ".git" ]; then
echo "📦 Pulling latest changes..."
git pull origin main || echo "⚠️ Git pull failed or not needed"
fi
# Setup database
echo "🛠️ Setting up the database..."
npx tsx scripts/setup-database.ts
# Build and deploy with Docker Compose
echo "🐳 Building and starting Docker containers..."
# Stop existing containers
docker-compose -f docker-compose.production.yml down || echo "No existing containers to stop"
# Build and start containers
docker-compose -f docker-compose.production.yml up -d --build
# Wait for containers to be healthy
echo "⏳ Waiting for containers to be healthy..."
sleep 30
# Check health
echo "🔍 Checking application health..."
for i in {1..10}; do
if curl -f http://localhost:3000/api/health >/dev/null 2>&1; then
echo "✅ Application is healthy!"
break
elif [ $i -eq 10 ]; then
echo "❌ Application health check failed after 10 attempts"
echo "📋 Container logs:"
docker-compose -f docker-compose.production.yml logs tt-booking
exit 1
else
echo "⏳ Attempt $i/10: Application not ready yet, waiting..."
sleep 10
fi
done
# Show running containers
echo "📊 Running containers:"
docker-compose -f docker-compose.production.yml ps
# Show logs
echo "📋 Recent application logs:"
docker-compose -f docker-compose.production.yml logs --tail=20 tt-booking
echo ""
echo "🎉 Deployment completed successfully!"
echo ""
echo "📊 Application Status:"
echo " • URL: https://lcc-tt-booking.mikicvi.com"
echo " • Health Check: http://localhost:3000/api/health"
echo " • Container Status: $(docker-compose -f docker-compose.production.yml ps -q tt-booking | xargs docker inspect -f '{{.State.Status}}')"
echo ""
echo "🔧 Useful commands:"
echo " • View logs: docker-compose -f docker-compose.production.yml logs -f tt-booking"
echo " • Restart: docker-compose -f docker-compose.production.yml restart tt-booking"
echo " • Stop: docker-compose -f docker-compose.production.yml down"
echo ""
echo "⚠️ Don't forget to:"
echo " 1. Set up Cloudflare Tunnel to expose your application"
echo " 2. Update your .env.production with real email credentials"
echo " 3. Change the default admin password"
echo ""
+97
View File
@@ -0,0 +1,97 @@
version: '3.8'
services:
tt-booking:
build:
context: .
dockerfile: Dockerfile
container_name: lcc-tt-booking
ports:
- '3000:3000'
environment:
- NODE_ENV=production
- DATABASE_URL=/app/data/sqlite.db
- NEXTAUTH_URL=https://lcc-tt-booking.mikicvi.com
- NEXTAUTH_SECRET=${NEXTAUTH_SECRET}
- EMAIL_USER=${EMAIL_USER}
- EMAIL_PASSWORD=${EMAIL_PASSWORD}
- ADMIN_EMAIL=${ADMIN_EMAIL}
- ADMIN_PASSWORD=${ADMIN_PASSWORD}
- PORT=3000
- RATE_LIMIT_MAX=${RATE_LIMIT_MAX:-100}
- RATE_LIMIT_WINDOW=${RATE_LIMIT_WINDOW:-900000}
- LOG_LEVEL=${LOG_LEVEL:-info}
volumes:
- ./data:/app/data
- ./backups:/app/backups
restart: unless-stopped
healthcheck:
test: ['CMD', 'curl', '-f', 'http://localhost:3000/api/health']
interval: 30s
timeout: 10s
retries: 3
start_period: 60s
networks:
- lcc-network
# Automated backup service
backup:
image: alpine:latest
container_name: lcc-backup
volumes:
- ./data:/data:ro
- ./backups:/backups
environment:
- TZ=Europe/Dublin
command: >
sh -c "
apk add --no-cache tzdata &&
while true; do
timestamp=$$(date +%Y%m%d-%H%M%S)
echo \"Creating backup at $$timestamp\"
cp /data/sqlite.db \"/backups/sqlite-$$timestamp.db\" 2>/dev/null || echo 'No database file found yet'
# Keep backups for 30 days
find /backups -name 'sqlite-*.db' -mtime +30 -delete 2>/dev/null || true
echo \"Backup completed, sleeping for 24 hours\"
sleep 86400
done"
restart: unless-stopped
depends_on:
- tt-booking
networks:
- lcc-network
# Log rotation service
logrotate:
image: alpine:latest
container_name: lcc-logrotate
volumes:
- ./logs:/logs
command: >
sh -c "
apk add --no-cache logrotate &&
echo '/logs/*.log {
daily
missingok
rotate 30
compress
delaycompress
notifempty
}' > /etc/logrotate.d/app &&
while true; do
logrotate /etc/logrotate.d/app
sleep 86400
done"
restart: unless-stopped
networks:
- lcc-network
networks:
lcc-network:
driver: bridge
volumes:
lcc-data:
driver: local
lcc-backups:
driver: local
+1 -1
View File
@@ -5,6 +5,6 @@ export default {
out: './lib/db/migrations',
driver: 'better-sqlite',
dbCredentials: {
url: './sqlite.db',
url: process.env.DATABASE_URL || './data/sqlite.db',
},
} satisfies Config;
+3 -1
View File
@@ -3,7 +3,9 @@ import { drizzle } from 'drizzle-orm/better-sqlite3';
import { migrate } from 'drizzle-orm/better-sqlite3/migrator';
import * as schema from './schema';
const sqlite = new Database('./sqlite.db');
// Get database path from environment variable or use default
const dbPath = process.env.DATABASE_URL || './data/sqlite.db';
const sqlite = new Database(dbPath);
export const db = drizzle(sqlite, { schema });
// Only run migrations if explicitly requested
+4
View File
@@ -8,6 +8,10 @@ const nextConfig = {
},
],
},
// Enable standalone output for Docker production builds
output: process.env.NODE_ENV === 'production' ? 'standalone' : undefined,
// External packages for better SQLite3 compatibility (Next.js 15+ syntax)
serverExternalPackages: ['better-sqlite3'],
};
module.exports = nextConfig;
+2 -1
View File
@@ -5,7 +5,8 @@ import { sql, eq } from 'drizzle-orm';
import { randomUUID } from 'crypto';
import bcrypt from 'bcryptjs';
const sqlite = new Database('./sqlite.db');
const dbPath = process.env.DATABASE_URL || './data/sqlite.db';
const sqlite = new Database(dbPath);
const db = drizzle(sqlite, { schema });
interface SetupOptions {
-41
View File
@@ -1,41 +0,0 @@
#!/usr/bin/env node
// Test script to verify Irish localization settings
console.log('🇮🇪 Testing Irish Localization Settings\n');
console.log('1. Week starts on Monday (Irish standard)');
console.log(' JavaScript getDay() values:');
console.log(' Sunday = 0, Monday = 1, ..., Saturday = 6');
console.log(' Irish display order should be: Monday, Tuesday, ..., Sunday\n');
// Test date formatting
const testDate = new Date('2025-09-25'); // This is a Thursday
console.log('2. Date Formatting Test:');
console.log(` Test date: ${testDate.toDateString()}`);
console.log(
` Irish format (en-IE): ${testDate.toLocaleDateString('en-IE', {
weekday: 'long',
year: 'numeric',
month: 'long',
day: 'numeric',
})}`
);
console.log(` Irish short format: ${testDate.toLocaleDateString('en-IE', { weekday: 'short' })}`);
console.log('\n3. Day of Week Conversion:');
const daysOfWeek = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
for (let jsDay = 0; jsDay <= 6; jsDay++) {
const irishDisplayOrder = jsDay === 0 ? 6 : jsDay - 1; // Convert Sunday(0) to position 6, others shift down
console.log(` JS Day ${jsDay} (${daysOfWeek[jsDay]}) -> Irish position ${irishDisplayOrder}`);
}
console.log('\n4. Week Structure for Admin Panel:');
const irishWeekOrder = [1, 2, 3, 4, 5, 6, 0]; // Monday through Sunday in JS values
irishWeekOrder.forEach((jsDay, displayIndex) => {
console.log(` Display position ${displayIndex}: ${daysOfWeek[jsDay]} (JS day ${jsDay})`);
});
console.log('\n✅ Irish localization configuration complete!');
console.log('📅 Calendar will now start with Monday');
console.log('🇮🇪 All dates will use en-IE locale format');
console.log('⏰ 24-hour time format maintained');
+67
View File
@@ -0,0 +1,67 @@
#!/bin/bash
# Cloudflare Tunnel Setup Script for LCC Table Tennis Booking
# Domain: lcc-tt-booking.mikicvi.com
set -e
DOMAIN="lcc-tt-booking.mikicvi.com"
TUNNEL_NAME="lcc-tt-booking"
echo "🌐 Setting up Cloudflare Tunnel for $DOMAIN"
echo ""
# Check if cloudflared is installed
if ! command -v cloudflared &> /dev/null; then
echo "📥 Installing cloudflared..."
# Detect architecture
ARCH=$(uname -m)
if [ "$ARCH" = "aarch64" ] || [ "$ARCH" = "arm64" ]; then
CLOUDFLARED_URL="https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-arm64"
elif [ "$ARCH" = "armv7l" ]; then
CLOUDFLARED_URL="https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-arm"
else
CLOUDFLARED_URL="https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64"
fi
# Download and install
curl -L --output cloudflared "$CLOUDFLARED_URL"
sudo mv cloudflared /usr/local/bin
sudo chmod +x /usr/local/bin/cloudflared
echo "✅ cloudflared installed successfully!"
else
echo "✅ cloudflared is already installed"
fi
echo ""
echo "🔐 Please follow these steps:"
echo ""
echo "1. Authenticate with Cloudflare:"
echo " cloudflared tunnel login"
echo ""
echo "2. Create the tunnel:"
echo " cloudflared tunnel create $TUNNEL_NAME"
echo ""
echo "3. Copy the tunnel ID from the output and update cloudflare-tunnel-config.yml"
echo ""
echo "4. Create DNS record:"
echo " cloudflared tunnel route dns $TUNNEL_NAME $DOMAIN"
echo ""
echo "5. Copy the config to cloudflared directory:"
echo " mkdir -p ~/.cloudflared"
echo " cp cloudflare-tunnel-config.yml ~/.cloudflared/config.yml"
echo " # Update <your-tunnel-id> in the config file with your actual tunnel ID"
echo ""
echo "6. Test the tunnel:"
echo " cloudflared tunnel run $TUNNEL_NAME"
echo ""
echo "7. Install as a service (optional):"
echo " sudo cloudflared service install"
echo " sudo systemctl enable cloudflared"
echo " sudo systemctl start cloudflared"
echo ""
echo "📋 Tunnel configuration template is available in: cloudflare-tunnel-config.yml"
echo "🚀 After setup, your app will be available at: https://$DOMAIN"
echo ""