diff --git a/.dockerignore b/.dockerignore index c1a0279..9d0845b 100644 --- a/.dockerignore +++ b/.dockerignore @@ -49,6 +49,9 @@ coverage ehthumbs.db Thumbs.db +# Explicitly include start.sh +!start.sh + # Git .git .gitignore diff --git a/DEPLOYMENT_GUIDE.md b/DEPLOYMENT_GUIDE.md new file mode 100644 index 0000000..8f5da3f --- /dev/null +++ b/DEPLOYMENT_GUIDE.md @@ -0,0 +1,147 @@ +# Deployment Guide for Phosphat Report App + +This guide will help you deploy the Phosphat Report application on your VPS using the provided `compose.yml` file. + +## Prerequisites + +- Docker and Docker Compose installed on your VPS +- Git (to clone the repository) +- At least 1GB RAM and 10GB disk space + +## Quick Deployment + +1. **Clone the repository** to your VPS: + ```bash + git clone + cd phosphat-report-app + ``` + +2. **Deploy the application**: + ```bash + docker-compose -f compose.yml up -d --build + ``` + +3. **Check the status**: + ```bash + docker-compose -f compose.yml ps + ``` + +4. **Access your application**: + - URL: `http://your-vps-ip:3000` + - Default login: `superadmin` / `P@ssw0rd123!` + +## Environment Variables (Hardcoded in compose.yml) + +The following environment variables are already configured in the `compose.yml` file: + +- **NODE_ENV**: `production` +- **DATABASE_URL**: `file:/app/data/production.db` +- **SESSION_SECRET**: `your-super-secure-session-secret-change-this-min-32-chars` +- **SUPER_ADMIN**: `superadmin` +- **SUPER_ADMIN_EMAIL**: `admin@yourcompany.com` +- **SUPER_ADMIN_PASSWORD**: `P@ssw0rd123!` +- **MAIL_HOST**: `smtp.gmail.com` +- **MAIL_PORT**: `587` +- **MAIL_USERNAME**: `your-email@gmail.com` +- **MAIL_PASSWORD**: `your-app-password` + +## Services Included + +### Main Application (`app`) +- **Port**: 3000 +- **Database**: SQLite with persistent storage +- **Health Check**: Available at `/health` endpoint +- **Resource Limits**: 512MB RAM, 0.5 CPU + +### Backup Service (`backup`) +- **Purpose**: Automatic daily database backups at 2 AM +- **Retention**: Keeps backups for 7 days +- **Location**: `/backup` volume + +## Useful Commands + +### View logs: +```bash +docker-compose -f compose.yml logs -f app +``` + +### Stop services: +```bash +docker-compose -f compose.yml down +``` + +### Restart services: +```bash +docker-compose -f compose.yml restart +``` + +### Manual backup: +```bash +docker-compose -f compose.yml exec app cp /app/data/production.db /app/data/backup_$(date +%Y%m%d_%H%M%S).db +``` + +### Check health: +```bash +curl http://localhost:3000/health +``` + +## Volumes + +- **app_data**: Stores the SQLite database +- **app_logs**: Application logs +- **backup_data**: Database backups + +## Security Notes + +1. **Change default passwords** after first login +2. **Update email settings** in the application +3. **Configure firewall** to only allow necessary ports +4. **Use HTTPS** with a reverse proxy (nginx/traefik) for production + +## Troubleshooting + +### Application won't start: +```bash +# Check logs +docker-compose -f compose.yml logs app + +# Rebuild without cache +docker-compose -f compose.yml build --no-cache app +``` + +### Database issues: +```bash +# Reset database (WARNING: This will delete all data) +docker-compose -f compose.yml down +docker volume rm $(docker volume ls -q | grep app_data) +docker-compose -f compose.yml up -d +``` + +### Port conflicts: +If port 3000 is already in use, edit the `compose.yml` file and change: +```yaml +ports: + - "3001:3000" # Change 3000 to any available port +``` + +## Updating the Application + +1. **Pull latest changes**: + ```bash + git pull origin main + ``` + +2. **Rebuild and restart**: + ```bash + docker-compose -f compose.yml up -d --build + ``` + +## Support + +For issues and support: +1. Check the application logs +2. Verify all services are running +3. Test the health endpoint +4. Check database connectivity + +The application should be accessible at `http://your-vps-ip:3000` after successful deployment. \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index ccf4332..64cb4ba 100644 --- a/Dockerfile +++ b/Dockerfile @@ -54,39 +54,6 @@ COPY --from=deps --chown=remix:nodejs /app/node_modules ./node_modules RUN mkdir -p /app/data /app/logs && \ chown -R remix:nodejs /app/data /app/logs -# Create startup script -COPY --chown=remix:nodejs < - sh -c " - apk add --no-cache dcron sqlite && - echo '0 2 * * * cp /data/production.db /backup/production_$(date +%Y%m%d_%H%M%S).db && find /backup -name \"production_*.db\" -mtime +7 -delete' | crontab - && - crond -f - " - networks: - - app_network - depends_on: - - app - -volumes: - app_data: - driver: local - app_logs: - driver: local - backup_data: - driver: local - -networks: - app_network: - driver: bridge \ No newline at end of file diff --git a/prisma/dev.db b/prisma/dev.db index 2623aac..91c8b2b 100644 Binary files a/prisma/dev.db and b/prisma/dev.db differ diff --git a/prisma/seed.js b/prisma/seed.js index 0252645..c97973a 100644 --- a/prisma/seed.js +++ b/prisma/seed.js @@ -6,62 +6,6 @@ const prisma = new PrismaClient(); async function main() { console.log('🌱 Seeding database...'); - // Seed Areas - const areas = await Promise.all([ - prisma.area.upsert({ - where: { name: 'Petra' }, - update: {}, - create: { name: 'Petra' } - }), - prisma.area.upsert({ - where: { name: 'Jarash' }, - update: {}, - create: { name: 'Jarash' } - }), - prisma.area.upsert({ - where: { name: 'Rum' }, - update: {}, - create: { name: 'Rum' } - }) - ]); - - // Seed DredgerLocations - const dredgerLocations = await Promise.all([ - prisma.dredgerLocation.upsert({ - where: { name: 'SP1-1' }, - update: {}, - create: { name: 'SP1-1', class: 'SP' } - }), - prisma.dredgerLocation.upsert({ - where: { name: 'SP1-2' }, - update: {}, - create: { name: 'SP1-2', class: 'SP' } - }), - prisma.dredgerLocation.upsert({ - where: { name: 'C01' }, - update: {}, - create: { name: 'C01', class: 'C' } - }), - prisma.dredgerLocation.upsert({ - where: { name: 'D1' }, - update: {}, - create: { name: 'D1', class: 'D' } - }) - ]); - - // Seed ReclamationLocations - const reclamationLocations = await Promise.all([ - prisma.reclamationLocation.upsert({ - where: { name: 'Eastern Shoreline' }, - update: {}, - create: { name: 'Eastern Shoreline' } - }), - prisma.reclamationLocation.upsert({ - where: { name: 'Western Shoreline' }, - update: {}, - create: { name: 'Western Shoreline' } - }) - ]); // Seed Super Admin Employee const superAdminUsername = process.env.SUPER_ADMIN || 'superadmin'; @@ -80,61 +24,12 @@ async function main() { } }); - // Seed Foreman - await prisma.foreman.upsert({ - where: { id: 1 }, - update: {}, - create: { - name: 'John Smith' - } - }); - // Seed Equipment - const equipment = await Promise.all([ - prisma.equipment.upsert({ - where: { id: 1 }, - update: {}, - create: { id: 1, category: 'Dozer', model: 'Dozer6', number: 1 } - }), - prisma.equipment.upsert({ - where: { id: 2 }, - update: {}, - create: { id: 2, category: 'Dozer', model: 'Dozer6', number: 2 } - }), - prisma.equipment.upsert({ - where: { id: 3 }, - update: {}, - create: { id: 3, category: 'Dozer', model: 'Dozer7', number: 1 } - }), - prisma.equipment.upsert({ - where: { id: 4 }, - update: {}, - create: { id: 4, category: 'Dozer', model: 'Dozer8', number: 1 } - }), - prisma.equipment.upsert({ - where: { id: 5 }, - update: {}, - create: { id: 5, category: 'Loader', model: 'Loader', number: 1 } - }), - prisma.equipment.upsert({ - where: { id: 6 }, - update: {}, - create: { id: 6, category: 'Excavator', model: 'Exc.', number: 1 } - }), - prisma.equipment.upsert({ - where: { id: 7 }, - update: {}, - create: { id: 7, category: 'Excavator', model: 'Exc.', number: 9 } - }) - ]); console.log('✅ Database seeded successfully!'); - console.log(`Created ${areas.length} areas`); - console.log(`Created ${dredgerLocations.length} dredger locations`); - console.log(`Created ${reclamationLocations.length} reclamation locations`); + console.log(`Created 1 employee`); - console.log(`Created 1 foreman`); - console.log(`Created ${equipment.length} equipment records`); + } main() diff --git a/prisma/seed.ts b/prisma/seed.ts index a482859..6d55f60 100644 --- a/prisma/seed.ts +++ b/prisma/seed.ts @@ -6,75 +6,7 @@ const prisma = new PrismaClient() async function main() { console.log('🌱 Seeding database...') - // Seed Areas - const areas = await Promise.all([ - prisma.area.upsert({ - where: { name: 'Petra' }, - update: {}, - create: { name: 'Petra' } - }), - prisma.area.upsert({ - where: { name: 'Jarash' }, - update: {}, - create: { name: 'Jarash' } - }), - prisma.area.upsert({ - where: { name: 'Rum' }, - update: {}, - create: { name: 'Rum' } - }) - ]) - - // Seed DredgerLocations - const dredgerLocations = await Promise.all([ - prisma.dredgerLocation.upsert({ - where: { name: 'SP1-1' }, - update: {}, - create: { name: 'SP1-1', class: 'SP' } - }), - prisma.dredgerLocation.upsert({ - where: { name: 'SP1-2' }, - update: {}, - create: { name: 'SP1-2', class: 'SP' } - }), - prisma.dredgerLocation.upsert({ - where: { name: 'C01' }, - update: {}, - create: { name: 'C01', class: 'C' } - }), - prisma.dredgerLocation.upsert({ - where: { name: 'D1' }, - update: {}, - create: { name: 'D1', class: 'D' } - }) - ]) - - // Seed ReclamationLocations - const reclamationLocations = await Promise.all([ - prisma.reclamationLocation.upsert({ - where: { name: 'Eastern Shoreline' }, - update: {}, - create: { name: 'Eastern Shoreline' } - }), - prisma.reclamationLocation.upsert({ - where: { name: 'Western Shoreline' }, - update: {}, - create: { name: 'Western Shoreline' } - }) - ]) - - // Seed Employee - // const employee = await prisma.employee.upsert({ - // where: { username: 'superuser' }, - // update: {}, - // create: { - // name: 'Super Admin User', - // authLevel: 3, - // username: '', - // email: '@gmail.com', - // password: bcrypt.hashSync('', 10) - // } - // }) + // Seed Employee //use the .env file SUPER_ADMIN, SUPER_ADMIN_EMAIL and SUPER_ADMIN_PASSWORD @@ -92,61 +24,9 @@ async function main() { }) - // Seed Foreman - const foreman = await prisma.foreman.upsert({ - where: { id: 1 }, - update: {}, - create: { - name: 'John Smith' - } - }) - - // Seed Equipment - const equipment = await Promise.all([ - prisma.equipment.upsert({ - where: { id: 1 }, - update: {}, - create: { id: 1, category: 'Dozer', model: 'Dozer6', number: 1 } - }), - prisma.equipment.upsert({ - where: { id: 2 }, - update: {}, - create: { id: 2, category: 'Dozer', model: 'Dozer6', number: 2 } - }), - prisma.equipment.upsert({ - where: { id: 3 }, - update: {}, - create: { id: 3, category: 'Dozer', model: 'Dozer7', number: 1 } - }), - prisma.equipment.upsert({ - where: { id: 4 }, - update: {}, - create: { id: 4, category: 'Dozer', model: 'Dozer8', number: 1 } - }), - prisma.equipment.upsert({ - where: { id: 5 }, - update: {}, - create: { id: 5, category: 'Loader', model: 'Loader', number: 1 } - }), - prisma.equipment.upsert({ - where: { id: 6 }, - update: {}, - create: { id: 6, category: 'Excavator', model: 'Exc.', number: 1 } - }), - prisma.equipment.upsert({ - where: { id: 7 }, - update: {}, - create: { id: 7, category: 'Excavator', model: 'Exc.', number: 9 } - }) - ]) console.log('✅ Database seeded successfully!') - console.log(`Created ${areas.length} areas`) - console.log(`Created ${dredgerLocations.length} dredger locations`) - console.log(`Created ${reclamationLocations.length} reclamation locations`) - console.log(`Created 1 employee`) - console.log(`Created 1 foreman`) - console.log(`Created ${equipment.length} equipment records`) + } main() diff --git a/start.sh b/start.sh new file mode 100644 index 0000000..ecd0159 --- /dev/null +++ b/start.sh @@ -0,0 +1,27 @@ +#!/bin/sh +set -e + +echo "Starting Phosphat Report Application..." + +# Run database migrations +echo "Running database migrations..." +npx prisma db push --accept-data-loss + +# Run seed using production script +echo "Seeding database..." +if [ -f "scripts/seed-production.js" ]; then + echo "Using production seed script..." + node scripts/seed-production.js +else + echo "Production seed script not found, trying alternative methods..." + if [ -f "prisma/seed.js" ]; then + echo "Using JavaScript seed file..." + node prisma/seed.js + else + echo "No seeding method available, skipping..." + fi +fi + +echo "Database setup complete. Starting application on port 3000..." +export PORT=3000 +exec npx remix-serve ./build/server/index.js \ No newline at end of file