A modular web dashboard for managing robots and 3D printers with reservation, tracking, logging, and real-time monitoring capabilities.
- Node.js 20+
- npm or yarn
- Install dependencies:
npm install- Initialize the database:
npm run db:push
npm run db:seed- Start the development servers:
npm run devThe application will be available at:
- Frontend: http://localhost:5173
- Backend API: http://localhost:3001
- Email: admin@example.com
- Password: admin123
Change this password after first login. New users who register themselves get the read-only viewer role; promote them on the Users page (see REGISTRATION_ROLE / ALLOW_REGISTRATION in the configuration reference).
dash/
├── client/ # React frontend
│ ├── src/
│ │ ├── components/ # UI components
│ │ ├── pages/ # Page components
│ │ ├── services/ # API client
│ │ ├── store/ # Zustand state
│ │ └── types/ # TypeScript types
├── server/ # Node.js backend
│ ├── src/
│ │ ├── routes/ # API endpoints
│ │ ├── middleware/ # Auth middleware
│ │ └── socket/ # WebSocket handlers
│ └── prisma/
│ └── schema.prisma # Database schema
- Dashboard: Real-time machine status overview
- Calendar: Reservation scheduling system
- Machines: Add, edit, and monitor equipment
- Jobs & Logs: Track job history and activity
- Maintenance: Submit and manage repair requests
- Real-time: WebSocket updates for live status changes
- Frontend: React 18, TypeScript, Vite, Tailwind CSS
- Backend: Node.js, Express, TypeScript
- Database: SQLite with Prisma ORM
- Real-time: Socket.io
- Auth: JWT with bcrypt
npm run dev- Start both frontend and backend in development modenpm run build- Build for productionnpm run db:push- Push schema changes to databasenpm run db:seed- Seed database with sample datanpm run db:studio- Open Prisma Studio
POST /api/auth/register- Register new userPOST /api/auth/login- LoginGET /api/machines- List machinesPOST /api/machines- Create machineGET /api/reservations- List reservationsPOST /api/reservations- Create reservationGET /api/maintenance- List maintenance requestsPOST /api/maintenance- Submit maintenance request
- Node.js 20 or higher
- npm (comes with Node.js)
- Git
-
Clone the repository
git clone <your-repo-url> dash cd dash
-
Install dependencies
npm install
-
Configure environment files
# Copy the example server environment file (the client needs no .env; # it uses relative URLs and reads no VITE_* variables) cp server/.env.example server/.env
-
Initialize the database
npm run db:push npm run db:seed
-
Start development servers
npm run dev
-
Access the application
- Frontend: http://localhost:5173
- Backend API: http://localhost:3001
- Default login:
admin@example.com/admin123
For production deployment on Linux servers, use the automated deployment script:
-
Clone and deploy
git clone <your-repo-url> dash cd dash chmod +x scripts/*.sh ./scripts/deploy.sh
Run the script as the (unprivileged) user that should own the checkout and run the service — not as
sudo ./scripts/deploy.sh. It callssudoitself for the few system-level steps (package installs, the systemd unit, nginx); running the whole script as root would make the service and files root-owned.The deployment script will:
- Install Node.js 20 LTS (if needed)
- Install
libnss-resolveand enable LLMNR in systemd-resolved (adds theresolvemodule to thehosts:line of/etc/nsswitch.conf) for local hostname lookups - Create data directories
- Generate a secure
server/.env - Install dependencies
- Build client and server
- Create and start systemd service
-
Access the application
http://your-server-ip:3001 -
Manage the service
sudo systemctl start dash # Start sudo systemctl stop dash # Stop sudo systemctl restart dash # Restart sudo systemctl status dash # View status journalctl -u dash -f # View logs
-
Clone the repository
git clone <your-repo-url> dash cd dash
-
Install dependencies
npm install
-
Configure environment
copy server\.env.example server\.envEdit
server\.envand set a secureJWT_SECRET(the client needs no.env). -
Initialize database
npm run db:push npm run db:seed
-
Build for production
npm run build
-
Run the server
cd server node dist/index.jsFor running as a Windows service, consider using PM2 or NSSM.
./scripts/update.sh [OPTIONS]Options:
--reset- Fetch from origin, then hard-reset the working tree toorigin/<branch>(discarding local changes and commits; recommended for production servers)--stash- Automatically stash changes without prompting--branch <name>- Check out and update the given branch--help- Show help message
Examples:
# Interactive mode (prompts if there are local changes)
./scripts/update.sh
# Production mode (discards any local modifications)
./scripts/update.sh --reset
# Auto-stash mode (preserves changes, restores after update)
./scripts/update.sh --stashThis will pull latest changes, install dependencies, apply schema changes (prisma db push), rebuild, and restart the service. It also installs the mDNS/NetBIOS name-resolution packages (avahi-daemon, libnss-mdns, winbind) if they are missing and adds them to /etc/nsswitch.conf.
git pull
npm install
npm run db:push
npm run build
# Restart the serverRegular backups protect your data. Backups include the SQLite database, uploaded files, and configuration.
data/dash.dborserver/prisma/dev.db- SQLite databasedata/uploads/(and legacyserver/uploads/on Windows) - Uploaded filesserver/.env- Configuration (contains secrets; the archives are created with mode600on Linux — store them securely)
The archive layout is dash_backup_<timestamp>/ containing dash.db, uploads/, config/server.env and backup_info.json (a .tar.gz on Linux, a .zip on Windows). restore.sh accepts either format.
Using the batch script:
scripts\backup.batUsing PowerShell:
.\scripts\backup.ps1Backups are saved to the backups/ folder with timestamp: dash_backup_YYYYMMDD_HHMMSS.zip
Manual backup (stop the server first so the database copy is consistent):
mkdir backups
powershell Compress-Archive -Path server\prisma\dev.db,data\uploads,server\.env -DestinationPath backups\manual_backup.zipCreate a backup:
./scripts/backup.sh
# Output: data/backups/dash_backup_20240123_120000.tar.gzManual backup (stop the service first, or use sqlite3 data/dash.db ".backup snapshot.db" for a consistent copy of a live database):
mkdir -p data/backups
tar -czf data/backups/dash_backup_$(date +%Y%m%d_%H%M%S).tar.gz \
data/dash.db \
data/uploads \
server/.env# Enable daily backups at 2 AM
./scripts/setup-backup.sh --daily
# With SSH transfer to remote server
./scripts/setup-backup.sh --daily --ssh user@backup-server:/backups/dash
# Check status
./scripts/setup-backup.sh --status
# Disable automated backups
./scripts/setup-backup.sh --disable# Linux to Linux (SCP)
scp data/backups/dash_backup_*.tar.gz user@newmachine:/path/to/dash/
# Windows to Linux (using PowerShell with SSH)
scp backups\dash_backup_*.zip user@linux-server:/path/to/dash/backups/-
Stop the server if running
-
Extract the backup
Expand-Archive -Path backups\dash_backup_YYYYMMDD_HHMMSS.zip -DestinationPath restore_temp
The zip contains a
dash_backup_YYYYMMDD_HHMMSS\folder withdash.db,uploads\andconfig\server.env. -
Copy files to their locations (delete any stale
dev.db-journal/dev.db-wal/dev.db-shmnext to the database first)copy restore_temp\dash_backup_YYYYMMDD_HHMMSS\dash.db server\prisma\dev.db xcopy restore_temp\dash_backup_YYYYMMDD_HHMMSS\uploads data\uploads /E /I /Y copy restore_temp\dash_backup_YYYYMMDD_HHMMSS\config\server.env server\.env
Use
data\dash.dbinstead ofserver\prisma\dev.dbif yourDATABASE_URLpoints there. -
Restart the server
cd server node dist/index.js
Using the restore script:
./scripts/restore.sh data/backups/dash_backup_20240123_120000.tar.gzRestore without overwriting config:
./scripts/restore.sh data/backups/dash_backup_20240123_120000.tar.gz --no-configManual restore (prefer restore.sh, which does all of this for you):
# Stop the service
sudo systemctl stop dash
# Extract to a temp dir — the archive root is dash_backup_<timestamp>/, so
# never extract it to / directly
tmp=$(mktemp -d)
tar -xzf data/backups/dash_backup_20240123_120000.tar.gz -C "$tmp"
src="$tmp"/dash_backup_*
# Remove stale SQLite sidecars, then copy the database and the uploads CONTENTS
rm -f data/dash.db-journal data/dash.db-wal data/dash.db-shm
cp "$src"/dash.db data/dash.db
mkdir -p data/uploads
cp -r "$src"/uploads/. data/uploads/
# optional: cp "$src"/config/server.env server/.env
rm -rf "$tmp"
# Restart service
sudo systemctl start dash-
On the source machine: Create a fresh backup
./scripts/backup.sh
-
Transfer the backup to the new server
scp data/backups/dash_backup_*.tar.gz user@newserver:/tmp/ -
On the new server: Deploy and restore
# Clone and deploy git clone <your-repo-url> dash cd dash chmod +x scripts/*.sh ./scripts/deploy.sh # Stop service and restore data sudo systemctl stop dash ./scripts/restore.sh /tmp/dash_backup_*.tar.gz sudo systemctl start dash
| Variable | Description | Default |
|---|---|---|
PORT |
Server port | 3001 |
DATABASE_URL |
SQLite database path. Relative paths resolve against server/prisma/, so the default is server/prisma/dev.db; production uses an absolute path such as file:/home/scap/dash/data/dash.db |
file:./dev.db |
JWT_SECRET |
Secret key for JWT tokens. Required in production; the server refuses to start with the placeholder value | (generate with openssl rand -base64 32) |
NODE_ENV |
Environment mode (deploy.sh sets production) |
development |
DASH_DATA_DIR |
Data directory. Uploads are stored in DASH_DATA_DIR/uploads, which is what the backup scripts archive |
./data (set by deploy/update scripts) |
UPLOADS_DIR |
Override the uploads directory | DASH_DATA_DIR/uploads |
CLIENT_URL |
Origin allowed for Socket.io CORS. Only needed when the client is served from a different origin than the API (e.g. the Vite dev server); behind nginx or the built-in static serving it is same-origin | http://localhost:5173 |
TRUST_PROXY |
Express trust proxy setting, used to read the real client IP from X-Forwarded-For. The default trusts the local nginx; set e.g. 1 or a CIDR when a remote load balancer sits in front |
loopback |
REGISTRATION_ROLE |
Role given to self-registered users (viewer or operator). The first user is always admin |
viewer |
ALLOW_REGISTRATION |
Set to false to disable self sign-up (admins create accounts instead) |
true |
SMTP_HOST |
Email server (optional) | - |
SMTP_PORT |
Email port (optional) | - |
SMTP_USER |
Email username (optional) | - |
SMTP_PASS |
Email password (optional) | - |
SMTP_REQUIRE_TLS |
Set to true to refuse sending unless the SMTP server offers STARTTLS |
false |
SLACK_WEBHOOK_URL |
Slack notifications (optional) | - |
None. The client uses relative URLs (/api/..., Socket.io on /) and reads no VITE_* variables, so it needs no client/.env. In development Vite proxies API and socket requests to the server on port 3001; in production the Express server serves the built client and the API from the same origin (optionally behind nginx).
# Check logs
journalctl -u dash -n 100
# Check if port is in use
sudo lsof -i :3001
# Try running manually
cd /path/to/dash
node server/dist/index.js# Reset database (WARNING: deletes all data). There are no Prisma migrations
# in this project; the schema is applied with `prisma db push`.
sudo systemctl stop dash # production only
rm -f data/dash.db data/dash.db-journal # production: data/dash.db
# development: server/prisma/dev.db
cd server
npx prisma db push
npx prisma db seedsudo chown -R $USER:$USER /path/to/dash# Find process using port
# Linux:
lsof -i :3001
# Windows:
netstat -ano | findstr :3001
# Kill process (Linux)
kill -9 <PID>
# Kill process (Windows)
taskkill /PID <PID> /F- Detailed deployment scripts documentation: See scripts/README.md
- Database schema: See server/prisma/schema.prisma
- Server configuration reference: See server/.env.example