Improve TV display visibility and add Windows deployment guide

- Increased font sizes across dashboard for better TV readability
  - Headers: 72px (was 48px)
  - Event titles: 56px (was 38px)
  - Clock: 48px (was 36px)
  - Connection status: 28px (was 18px)
- Enhanced spacing and padding throughout
- Larger logo (160px vs 100px)
- Thicker borders for better visibility
- Added comprehensive Windows deployment documentation

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
cproudlock
2025-10-23 15:53:25 -04:00
parent 8e52a05c57
commit 81cb74cdef
2 changed files with 637 additions and 57 deletions

577
DEPLOYMENT_WINDOWS.md Normal file
View File

@@ -0,0 +1,577 @@
# Shopfloor Dashboard - Windows Production Deployment Guide
This guide covers deploying the Shopfloor Dashboard Node.js application to a Windows production server.
## Prerequisites
- Windows Server 2016 or later (or Windows 10/11)
- Administrative access to the server
- MySQL database access
- Internet connection for downloading Node.js
---
## 1. Install Node.js on Windows
### Option A: Using the Official Installer (Recommended)
1. **Download Node.js:**
- Go to https://nodejs.org/
- Download the **LTS (Long Term Support)** version for Windows
- Choose the Windows Installer (.msi) - 64-bit
2. **Run the Installer:**
- Double-click the downloaded `.msi` file
- Click "Next" through the setup wizard
- Accept the license agreement
- **Important:** Make sure "Add to PATH" is checked
- Install with default options
- Click "Finish" when complete
3. **Verify Installation:**
- Open Command Prompt or PowerShell
- Run these commands:
```cmd
node --version
npm --version
```
- You should see version numbers (e.g., v20.x.x and 10.x.x)
### Option B: Using Chocolatey (Package Manager)
If you have Chocolatey installed:
```powershell
# Run PowerShell as Administrator
choco install nodejs-lts -y
# Verify
node --version
npm --version
```
---
## 2. Deploy the Application Files
### Option A: Using Git (Recommended)
1. **Install Git for Windows:**
- Download from https://git-scm.com/download/win
- Run installer with default options
2. **Clone the Repository:**
```cmd
cd C:\inetpub\wwwroot
git clone http://localhost:3000/cproudlock/shopfloor-dashboard.git
cd shopfloor-dashboard
```
### Option B: Manual File Copy
1. **Create Application Directory:**
```cmd
mkdir C:\inetpub\wwwroot\shopfloor-dashboard
```
2. **Copy these files from development:**
- `server.js`
- `package.json`
- `package-lock.json`
- `public\` directory (entire folder)
- `.gitignore` (optional)
3. **Do NOT copy:**
- `node_modules\` (will be regenerated)
- `.git\` directory
- Any `.env` files with passwords
---
## 3. Install Dependencies
```cmd
cd C:\inetpub\wwwroot\shopfloor-dashboard
npm install --production
```
This will install:
- express
- mysql2
---
## 4. Configure Environment Variables
### Option A: Using Windows Environment Variables
1. **Open System Properties:**
- Right-click "This PC" → Properties
- Click "Advanced system settings"
- Click "Environment Variables"
2. **Add System Variables:**
- Click "New" under System Variables
- Add each variable:
```
Variable Name: PORT
Variable Value: 3001
Variable Name: DB_HOST
Variable Value: localhost (or your database server IP)
Variable Name: DB_PORT
Variable Value: 3306
Variable Name: DB_USER
Variable Value: 570005354 (or your production user)
Variable Name: DB_PASS
Variable Value: your-secure-password
Variable Name: DB_NAME
Variable Value: shopdb
Variable Name: NODE_ENV
Variable Value: production
```
3. **Apply and restart Command Prompt**
### Option B: Using a .env File (Less Secure)
Create `config.js` in the project root:
```javascript
module.exports = {
port: process.env.PORT || 3001,
db: {
host: process.env.DB_HOST || 'localhost',
port: process.env.DB_PORT || 3306,
user: process.env.DB_USER || '570005354',
password: process.env.DB_PASS || 'your-password',
database: process.env.DB_NAME || 'shopdb'
}
};
```
**Security Warning:** Never commit passwords to Git!
---
## 5. Test the Application
```cmd
cd C:\inetpub\wwwroot\shopfloor-dashboard
node server.js
```
You should see:
```
Shopfloor Dashboard running on port 3001
Access at: http://localhost:3001
```
Open a browser and test:
- http://localhost:3001 (main dashboard)
- http://localhost:3001/api/notifications (API endpoint)
- http://localhost:3001/health (health check)
Press `Ctrl+C` to stop the test.
---
## 6. Set Up as a Windows Service
To run the dashboard automatically and keep it running, you need to set it up as a Windows service.
### Option A: Using PM2 (Recommended)
**Install PM2:**
```cmd
npm install -g pm2
npm install -g pm2-windows-startup
```
**Configure PM2 Windows Service:**
```cmd
# Set up PM2 to run at startup
pm2-startup install
# Start the application
cd C:\inetpub\wwwroot\shopfloor-dashboard
pm2 start server.js --name shopfloor-dashboard
# Save the PM2 configuration
pm2 save
```
**Useful PM2 Commands:**
```cmd
pm2 status # Check status
pm2 logs shopfloor-dashboard # View logs
pm2 restart shopfloor-dashboard # Restart app
pm2 stop shopfloor-dashboard # Stop app
pm2 delete shopfloor-dashboard # Remove from PM2
pm2 monit # Real-time monitoring
```
**PM2 Log Locations:**
```
C:\Users\<username>\.pm2\logs\
```
### Option B: Using NSSM (Non-Sucking Service Manager)
**Download and Install NSSM:**
1. Download from https://nssm.cc/download
2. Extract to `C:\nssm\`
3. Add to PATH or use full path
**Create the Service:**
```cmd
# Navigate to NSSM directory
cd C:\nssm\win64
# Install service
nssm install ShopfloorDashboard "C:\Program Files\nodejs\node.exe" "C:\inetpub\wwwroot\shopfloor-dashboard\server.js"
# Set working directory
nssm set ShopfloorDashboard AppDirectory C:\inetpub\wwwroot\shopfloor-dashboard
# Set environment variables
nssm set ShopfloorDashboard AppEnvironmentExtra PORT=3001 DB_HOST=localhost DB_USER=570005354 DB_PASS=your-password DB_NAME=shopdb
# Set startup type to automatic
nssm set ShopfloorDashboard Start SERVICE_AUTO_START
# Start the service
nssm start ShopfloorDashboard
```
**Manage the Service:**
```cmd
# Using NSSM
nssm stop ShopfloorDashboard
nssm start ShopfloorDashboard
nssm restart ShopfloorDashboard
nssm status ShopfloorDashboard
nssm remove ShopfloorDashboard
# Or using Windows Services
services.msc # Opens Services window
```
### Option C: Using Windows Task Scheduler
1. **Open Task Scheduler**
2. **Create Basic Task:**
- Name: Shopfloor Dashboard
- Trigger: At system startup
- Action: Start a program
- Program: `C:\Program Files\nodejs\node.exe`
- Arguments: `C:\inetpub\wwwroot\shopfloor-dashboard\server.js`
- Start in: `C:\inetpub\wwwroot\shopfloor-dashboard`
3. **Properties:**
- Run whether user is logged on or not
- Run with highest privileges
- Configure for: Windows Server 2016 or later
---
## 7. Configure Windows Firewall
```powershell
# Run PowerShell as Administrator
# Allow port 3001
New-NetFirewallRule -DisplayName "Shopfloor Dashboard" -Direction Inbound -LocalPort 3001 -Protocol TCP -Action Allow
# Or if using IIS reverse proxy, allow port 80/443
New-NetFirewallRule -DisplayName "HTTP" -Direction Inbound -LocalPort 80 -Protocol TCP -Action Allow
New-NetFirewallRule -DisplayName "HTTPS" -Direction Inbound -LocalPort 443 -Protocol TCP -Action Allow
```
---
## 8. Set Up IIS Reverse Proxy (Optional)
If you want to use IIS as a reverse proxy to add SSL or run on port 80:
### Install Required IIS Components:
```powershell
# Run PowerShell as Administrator
Install-WindowsFeature -name Web-Server -IncludeManagementTools
```
### Install URL Rewrite and ARR:
1. **Download and install:**
- URL Rewrite Module: https://www.iis.net/downloads/microsoft/url-rewrite
- Application Request Routing (ARR): https://www.iis.net/downloads/microsoft/application-request-routing
2. **Enable ARR Proxy:**
- Open IIS Manager
- Click server name in left panel
- Double-click "Application Request Routing Cache"
- Click "Server Proxy Settings" in right panel
- Check "Enable proxy"
- Click Apply
3. **Configure URL Rewrite:**
- In IIS Manager, select Default Web Site (or create new site)
- Double-click "URL Rewrite"
- Click "Add Rule(s)" → "Reverse Proxy"
- Enter: `localhost:3001`
- Click OK
Now access the dashboard at:
- http://your-server-name or http://server-ip
---
## 9. Database Configuration
Ensure MySQL is accessible:
### If MySQL is on the same server:
```sql
-- Connect to MySQL
mysql -u root -p
-- Grant permissions
GRANT ALL PRIVILEGES ON shopdb.* TO '570005354'@'localhost' IDENTIFIED BY 'your-secure-password';
FLUSH PRIVILEGES;
```
### If MySQL is on a remote server:
```sql
-- On the database server
GRANT ALL PRIVILEGES ON shopdb.* TO '570005354'@'windows-server-ip' IDENTIFIED BY 'your-secure-password';
FLUSH PRIVILEGES;
```
### Test Database Connection:
```cmd
cd C:\inetpub\wwwroot\shopfloor-dashboard
node -e "const mysql = require('mysql2'); const conn = mysql.createConnection({host:'localhost',user:'570005354',password:'your-password',database:'shopdb'}); conn.connect((err) => {if(err) console.error('Error:',err); else console.log('Connected!'); conn.end();});"
```
---
## 10. Monitoring and Logs
### Using Event Viewer (Windows):
1. Open Event Viewer (`eventvwr.msc`)
2. Navigate to: Windows Logs → Application
3. Look for Node.js or your service name
### Using PM2:
```cmd
# View real-time logs
pm2 logs shopfloor-dashboard
# View specific log files
pm2 logs shopfloor-dashboard --lines 100
# Clear logs
pm2 flush
```
### Custom Logging:
Add to `server.js` for file logging:
```javascript
const fs = require('fs');
const path = require('path');
// Create logs directory if it doesn't exist
const logDir = path.join(__dirname, 'logs');
if (!fs.existsSync(logDir)) {
fs.mkdirSync(logDir);
}
// Log to file
const logFile = path.join(logDir, `app-${new Date().toISOString().split('T')[0]}.log`);
const logStream = fs.createWriteStream(logFile, { flags: 'a' });
// Override console.log
const originalLog = console.log;
console.log = function(...args) {
const timestamp = new Date().toISOString();
const message = `[${timestamp}] ${args.join(' ')}\n`;
logStream.write(message);
originalLog.apply(console, args);
};
```
---
## 11. Security Checklist
- [ ] Change default database passwords
- [ ] Use Windows environment variables (not hardcoded passwords)
- [ ] Enable Windows Firewall with only necessary ports
- [ ] Set up SSL certificate if exposing to internet
- [ ] Run Node.js service under limited user account (not Administrator)
- [ ] Keep Node.js updated regularly
- [ ] Set up automated database backups
- [ ] Restrict database access to application server only
- [ ] Review Windows Event Logs regularly
- [ ] Enable Windows Defender or antivirus
---
## 12. Updating the Application
### Using Git:
```cmd
cd C:\inetpub\wwwroot\shopfloor-dashboard
git pull origin main
npm install --production
# If using PM2:
pm2 restart shopfloor-dashboard
# If using NSSM:
nssm restart ShopfloorDashboard
```
### Manual Update:
1. Stop the service
2. Replace changed files
3. Run `npm install --production` if dependencies changed
4. Start the service
---
## 13. Troubleshooting
### Application won't start:
```cmd
# Check Node.js version
node --version
# Check for errors
cd C:\inetpub\wwwroot\shopfloor-dashboard
node server.js
```
### Can't connect to database:
```cmd
# Test MySQL connection
mysql -h localhost -u 570005354 -p shopdb
# Check Windows Firewall
# Check MySQL is running: services.msc
```
### Port already in use:
```powershell
# Find what's using port 3001
netstat -ano | findstr :3001
# Kill the process (replace PID with actual number)
taskkill /PID <pid> /F
```
### Service won't start automatically:
- Check Windows Event Viewer for errors
- Verify service is set to "Automatic" startup
- Check environment variables are set correctly
- Verify file paths are correct
### Can't access from other computers:
- Check Windows Firewall rules
- Verify application is listening on 0.0.0.0 (not just 127.0.0.1)
- Test with: `netstat -an | findstr :3001`
---
## 14. Performance Optimization
### For Production:
1. **Set NODE_ENV:**
```cmd
setx NODE_ENV production /M
```
2. **Increase Process Priority (if using NSSM):**
```cmd
nssm set ShopfloorDashboard AppPriority ABOVE_NORMAL_PRIORITY_CLASS
```
3. **Configure PM2 Cluster Mode (multiple instances):**
```cmd
pm2 start server.js -i max --name shopfloor-dashboard
```
---
## Quick Reference
### Application Paths:
```
Application: C:\inetpub\wwwroot\shopfloor-dashboard
Node.js: C:\Program Files\nodejs
PM2 Logs: C:\Users\<username>\.pm2\logs
```
### URLs:
```
Dashboard: http://localhost:3001
API: http://localhost:3001/api/notifications
Health: http://localhost:3001/health
```
### Common Commands:
```cmd
# Start manually
node server.js
# PM2
pm2 start server.js --name shopfloor-dashboard
pm2 status
pm2 logs shopfloor-dashboard
pm2 restart shopfloor-dashboard
# NSSM
nssm start ShopfloorDashboard
nssm stop ShopfloorDashboard
nssm restart ShopfloorDashboard
nssm status ShopfloorDashboard
```
---
## Support
For issues or questions:
- Check Windows Event Viewer: `eventvwr.msc`
- Check application logs: PM2 or custom logs
- Review README.md for application details
- Contact: IT Support - West Jefferson
---
**Last Updated:** October 2025
**Version:** 1.0.0

View File

@@ -22,20 +22,20 @@
} }
.container { .container {
max-width: 1920px; max-width: 100%;
margin: 0 auto; margin: 0 auto;
padding: 30px 40px; padding: 50px 60px;
padding-bottom: 100px; padding-bottom: 150px;
} }
.header { .header {
display: grid; display: grid;
grid-template-columns: auto 1fr auto; grid-template-columns: auto 1fr auto;
align-items: center; align-items: center;
gap: 40px; gap: 60px;
margin-bottom: 40px; margin-bottom: 60px;
border-bottom: 2px solid #4181ff; /* GE Sky Blue */ border-bottom: 4px solid #4181ff; /* GE Sky Blue */
padding-bottom: 25px; padding-bottom: 40px;
} }
.logo-container { .logo-container {
@@ -44,7 +44,7 @@
} }
.logo-container img { .logo-container img {
height: 100px; height: 160px;
width: auto; width: auto;
} }
@@ -52,47 +52,48 @@
text-align: center; text-align: center;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 8px; gap: 15px;
} }
.location-title { .location-title {
font-size: 18px; font-size: 32px;
font-weight: 600; font-weight: 600;
color: #eaeaea; /* GE Tungsten */ color: #eaeaea; /* GE Tungsten */
text-transform: uppercase; text-transform: uppercase;
letter-spacing: 2px; letter-spacing: 3px;
} }
.header-center h1 { .header-center h1 {
font-size: 48px; font-size: 72px;
font-weight: 700; font-weight: 700;
text-transform: uppercase; text-transform: uppercase;
letter-spacing: 2px; letter-spacing: 3px;
color: #fff; color: #fff;
} }
.clock { .clock {
font-size: 36px; font-size: 48px;
font-weight: 600; font-weight: 600;
letter-spacing: 1px; letter-spacing: 1px;
color: #4181ff; /* GE Sky Blue */ color: #4181ff; /* GE Sky Blue */
text-align: right; text-align: right;
line-height: 1.3;
} }
.connection-status { .connection-status {
position: fixed; position: fixed;
top: 20px; top: 30px;
right: 20px; right: 30px;
padding: 12px 20px; padding: 20px 35px;
border-radius: 6px; border-radius: 10px;
font-size: 18px; font-size: 28px;
font-weight: 700; font-weight: 700;
z-index: 1000; z-index: 1000;
display: flex; display: flex;
align-items: center; align-items: center;
gap: 10px; gap: 15px;
text-transform: uppercase; text-transform: uppercase;
letter-spacing: 0.5px; letter-spacing: 1px;
} }
.connection-status.connected { .connection-status.connected {
@@ -111,25 +112,25 @@
} }
.status-dot { .status-dot {
width: 12px; width: 18px;
height: 12px; height: 18px;
border-radius: 50%; border-radius: 50%;
background: #00003d; background: #00003d;
} }
.events-section { .events-section {
margin-bottom: 40px; margin-bottom: 60px;
} }
.section-title { .section-title {
font-size: 42px; font-size: 64px;
font-weight: 800; font-weight: 800;
margin-bottom: 25px; margin-bottom: 40px;
padding: 15px 25px; padding: 25px 40px;
border-radius: 8px; border-radius: 12px;
display: inline-block; display: inline-block;
text-transform: uppercase; text-transform: uppercase;
letter-spacing: 1px; letter-spacing: 2px;
} }
.section-title.current { .section-title.current {
@@ -147,11 +148,11 @@
.event-card { .event-card {
background: #fff; background: #fff;
color: #000; color: #000;
padding: 30px 40px; padding: 50px 60px;
margin-bottom: 20px; margin-bottom: 35px;
border-radius: 8px; border-radius: 12px;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15); box-shadow: 0 6px 30px rgba(0, 0, 0, 0.15);
border-left: 8px solid; border-left: 15px solid;
transition: all 0.3s ease; transition: all 0.3s ease;
} }
@@ -177,33 +178,35 @@
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
margin-bottom: 20px; margin-bottom: 30px;
gap: 20px; gap: 30px;
} }
.event-title { .event-title {
font-size: 38px; font-size: 56px;
font-weight: 700; font-weight: 700;
flex: 1; flex: 1;
color: #00003d; /* GE Deep Navy for text */ color: #00003d; /* GE Deep Navy for text */
line-height: 1.2;
} }
.event-ticket { .event-ticket {
font-size: 32px; font-size: 48px;
font-weight: 700; font-weight: 700;
background: #00003d; /* GE Deep Navy */ background: #00003d; /* GE Deep Navy */
color: #fff; color: #fff;
padding: 10px 25px; padding: 15px 35px;
border-radius: 6px; border-radius: 10px;
white-space: nowrap; white-space: nowrap;
text-transform: uppercase; text-transform: uppercase;
letter-spacing: 0.5px; letter-spacing: 1px;
} }
.event-time { .event-time {
font-size: 26px; font-size: 38px;
color: #666; color: #666;
font-weight: 400; font-weight: 400;
line-height: 1.5;
} }
.event-time strong { .event-time strong {
@@ -213,12 +216,12 @@
.no-events { .no-events {
text-align: center; text-align: center;
font-size: 36px; font-size: 52px;
font-weight: 600; font-weight: 600;
padding: 80px 40px; padding: 120px 60px;
background: rgba(234, 234, 234, 0.1); background: rgba(234, 234, 234, 0.1);
border-radius: 8px; border-radius: 12px;
margin-top: 30px; margin-top: 50px;
color: #eaeaea; /* GE Tungsten */ color: #eaeaea; /* GE Tungsten */
} }
@@ -229,31 +232,31 @@
right: 0; right: 0;
background: rgba(0, 0, 0, 0.8); background: rgba(0, 0, 0, 0.8);
text-align: center; text-align: center;
padding: 15px; padding: 25px;
font-size: 22px; font-size: 32px;
z-index: 999; z-index: 999;
font-weight: 500; font-weight: 500;
} }
.loading { .loading {
text-align: center; text-align: center;
font-size: 36px; font-size: 52px;
font-weight: 600; font-weight: 600;
padding: 80px 40px; padding: 120px 60px;
background: rgba(234, 234, 234, 0.1); background: rgba(234, 234, 234, 0.1);
border-radius: 8px; border-radius: 12px;
margin-top: 30px; margin-top: 50px;
} }
.error-message { .error-message {
background: #dc3545; background: #dc3545;
color: #fff; color: #fff;
padding: 40px; padding: 60px;
border-radius: 8px; border-radius: 12px;
text-align: center; text-align: center;
font-size: 32px; font-size: 48px;
font-weight: 700; font-weight: 700;
margin: 30px 0; margin: 50px 0;
} }
</style> </style>
</head> </head>
@@ -425,7 +428,7 @@
container.innerHTML = ` container.innerHTML = `
<div class="error-message"> <div class="error-message">
⚠️ Unable to load events<br> ⚠️ Unable to load events<br>
<span style="font-size: 24px; margin-top: 10px; display: block;">Retrying...</span> <span style="font-size: 36px; margin-top: 20px; display: block;">Retrying...</span>
</div> </div>
`; `;
} }