547 lines
16 KiB
Markdown
547 lines
16 KiB
Markdown
# Deathwatch Roller - Development & Operations Guide
|
|
|
|
Complete documentation for building, testing, deploying, and maintaining the Deathwatch Roller application. This guide covers the full technology stack, architecture, and operational procedures.
|
|
|
|
## Project Overview
|
|
Deathwatch Roller is a full-stack web application for managing tabletop RPG gameplay. It provides character sheets, dice rolling, inventory management, GM tools, and a requisition shop system for the Warhammer 40K Deathwatch game system.
|
|
|
|
## Technology Stack
|
|
|
|
### Frontend
|
|
- **Framework**: React 18.2.0
|
|
- **Styling**: Tailwind CSS
|
|
- **Testing**: Jest + React Testing Library
|
|
- **Build Tool**: create-react-app (react-scripts)
|
|
- **State Management**: React hooks (useState, useCallback, useEffect)
|
|
- **HTTP Client**: Axios
|
|
|
|
### Backend
|
|
- **Runtime**: Node.js
|
|
- **Framework**: Express.js 5.1.0
|
|
- **Database**: MariaDB
|
|
- **Security**: bcrypt, CORS, custom session validation
|
|
- **File Processing**: PDF-parse (for importing game data)
|
|
|
|
### DevOps
|
|
- **Process Management**: PM2 (backend server)
|
|
- **Frontend Serving**: serve (static file server on port 3000)
|
|
- **Backend API**: Running on port 5000
|
|
- **Build Output**: Production builds in `/build` directory
|
|
|
|
## Architecture Overview
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────────┐
|
|
│ CLIENT (React) │
|
|
│ - Player Tab (character sheets, inventory) │
|
|
│ - Dice Roller (d100 rolls with modifiers) │
|
|
│ - Requisition Shop (purchase equipment with RP) │
|
|
│ - Bestiary (enemy database and stats) │
|
|
│ - Rules (searchable game rules reference) │
|
|
│ - GM Kit (enemy generation, bulk operations) │
|
|
│ - Player Management (admin panel for GMs) │
|
|
│ Port: 3000 (via serve or npm start) │
|
|
└────────────┬────────────────────────────────────────────────┘
|
|
│
|
|
HTTP/CORS
|
|
│
|
|
┌────────────▼────────────────────────────────────────────────┐
|
|
│ BACKEND (Express) │
|
|
│ API Routes: │
|
|
│ - /api/players - Player CRUD & character data │
|
|
│ - /api/sessions - Session validation & authentication │
|
|
│ - /api/shop - Requisition shop purchases │
|
|
│ - /api/rules - Game rules database access │
|
|
│ - /api/weapons - Weapon stats & properties │
|
|
│ - /api/bestiary - Enemy database access │
|
|
│ - /api/gmkit - GM tools & bulk operations │
|
|
│ Port: 5000 │
|
|
└────────────┬────────────────────────────────────────────────┘
|
|
│
|
|
SQL Queries
|
|
│
|
|
┌────────────▼────────────────────────────────────────────────┐
|
|
│ MariaDB Database │
|
|
│ Tables: │
|
|
│ - players (character data, RP, XP, renown) │
|
|
│ - sessions (authentication) │
|
|
│ - weapons (weapon stats & costs) │
|
|
│ - rules (game rules reference) │
|
|
│ - bestiary (enemy data) │
|
|
└─────────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
## Project Structure
|
|
|
|
```
|
|
dwroller/
|
|
├── src/
|
|
│ ├── components/ # React UI components
|
|
│ │ ├── PlayerManagement.jsx # GM admin panel
|
|
│ │ ├── PlayerTab.jsx # Player character sheet
|
|
│ │ ├── DeathwatchRoller.jsx # Dice rolling interface
|
|
│ │ ├── RequisitionShop.jsx # Equipment shop
|
|
│ │ ├── BestiaryTab.jsx # Enemy database
|
|
│ │ ├── RulesTab.jsx # Rules reference
|
|
│ │ ├── GMKit.jsx # GM tools
|
|
│ │ ├── XPBar.jsx # Experience progress bar
|
|
│ │ └── GMKit_old.jsx # Legacy (unused)
|
|
│ ├── utils/
|
|
│ │ └── logger.js # Logging utility
|
|
│ ├── tests/
|
|
│ │ ├── bestiaryTab.test.js
|
|
│ │ ├── login.test.js
|
|
│ │ ├── playerManagement.test.js
|
|
│ │ └── requisitionShop.test.js
|
|
│ ├── App.js # Main app with routing
|
|
│ ├── App.css # App styling
|
|
│ ├── index.js # React entry point
|
|
│ ├── index.css # Global Tailwind styles
|
|
│ └── index.html # HTML template
|
|
├── database/
|
|
│ ├── server.js # Express API server
|
|
│ ├── mariadb.js # Database connection
|
|
│ ├── sessionModel.js # Session management
|
|
│ ├── pm2.config.js # PM2 configuration
|
|
│ ├── requireSession.js # Auth middleware
|
|
│ ├── shop-helpers.js # Shop business logic
|
|
│ ├── switch-db.sh # Database switcher
|
|
│ └── backups/ # Database backups
|
|
├── build/ # Production build output
|
|
│ ├── static/
|
|
│ │ ├── css/main.*.css # Compiled Tailwind
|
|
│ │ └── js/ # Bundled JavaScript
|
|
│ └── index.html # Served HTML
|
|
├── backup-scripts/ # Utility scripts
|
|
│ ├── migrate-to-sqlite.js
|
|
│ ├── sync-skills-csv-to-db.js
|
|
│ └── ...
|
|
├── package.json # Dependencies & scripts
|
|
├── tailwind.config.js # Tailwind configuration
|
|
├── jest.config.js # Jest test configuration
|
|
├── eslint.config.js # ESLint configuration
|
|
└── README.md # Project readme
|
|
```
|
|
|
|
## Build Process
|
|
|
|
### Local Development
|
|
```bash
|
|
# Install dependencies
|
|
npm install
|
|
|
|
# Start dev server with hot reload
|
|
npm start
|
|
# or
|
|
npm run dev
|
|
```
|
|
|
|
### Build Steps
|
|
|
|
**1. Run Tests**
|
|
```bash
|
|
npm run test:unit
|
|
# Runs all unit tests using Jest
|
|
```
|
|
|
|
**2. Build for Production**
|
|
```bash
|
|
npm run build
|
|
# Executes: npm run test:unit && react-scripts build
|
|
# Creates optimized production bundle in /build
|
|
```
|
|
|
|
**3. Verify Build Output**
|
|
```bash
|
|
# Check that build directory was created with static files
|
|
ls -la build/static/css/
|
|
ls -la build/static/js/
|
|
|
|
# Verify CSS size and integrity
|
|
gzip -c build/static/css/main.*.css | wc -c
|
|
# Expected: ~6-7 KB gzipped
|
|
```
|
|
|
|
### Build Configuration
|
|
- **Source Maps**: Generated for debugging
|
|
- **CSS Minification**: Automatic via react-scripts
|
|
- **JS Minification**: Webpack tree-shaking + uglification
|
|
- **Public Path**: Set to `/` for root-level deployment
|
|
|
|
### Alternative Build Commands
|
|
```bash
|
|
# Fast build without tests (use carefully)
|
|
npm run build:fast
|
|
|
|
# Build with integration tests
|
|
npm run build:with-integration
|
|
|
|
# Test -> Build -> Test cycle
|
|
npm run test-build-test
|
|
```
|
|
|
|
## Deployment Process
|
|
|
|
### 1. Build for Production
|
|
```bash
|
|
cd /home/alex/git/dwroller
|
|
npm run build
|
|
# Output: /build directory ready for deployment
|
|
```
|
|
|
|
### 2. Start Frontend Server
|
|
```bash
|
|
# Serve the production build on port 3000
|
|
npx serve -s build -l 3000 &
|
|
|
|
# Or with PM2 (optional)
|
|
pm2 start "npx serve -s build -l 3000" --name dwroller-frontend
|
|
pm2 save
|
|
```
|
|
|
|
### 3. Ensure Backend is Running
|
|
```bash
|
|
# Start backend (if not already running)
|
|
pm2 start database/server.js --name deathwatch-server
|
|
|
|
# Verify it's running
|
|
pm2 list
|
|
pm2 logs deathwatch-server
|
|
```
|
|
|
|
### 4. Verify The Live Site
|
|
After a production build and PM2 reload, open `https://dwroller.alw.dk` and
|
|
check the exact flow you changed on the deployed site. A successful local build
|
|
or PM2 reload is not enough by itself; live-site verification is required for
|
|
changes that affect production behavior.
|
|
|
|
### 5. Verify Deployment
|
|
```bash
|
|
# Test frontend accessibility
|
|
curl http://localhost:3000
|
|
|
|
# Test API connectivity
|
|
curl http://localhost:5000/api/players
|
|
|
|
# Check both are running
|
|
ps aux | grep -E "serve|node"
|
|
```
|
|
|
|
## Testing
|
|
|
|
### Unit Tests
|
|
```bash
|
|
npm run test:unit
|
|
# Runs Jest with --runInBand to avoid conflicts
|
|
```
|
|
|
|
**Current Test Status:**
|
|
- ✅ 13 tests passing
|
|
- ⚠️ 12 tests failing (pre-existing, architectural issues)
|
|
- Tests cover: login, requisition shop, bestiary, player management
|
|
|
|
### Running Specific Tests
|
|
```bash
|
|
# Run a specific test file
|
|
npm test -- src/tests/login.test.js
|
|
|
|
# Run tests matching a pattern
|
|
npm test -- --testNamePattern="PlayerManagement"
|
|
|
|
# Watch mode (automatic re-run on file changes)
|
|
npm test -- --watch
|
|
```
|
|
|
|
### Test Coverage
|
|
```bash
|
|
npm test -- --coverage
|
|
# Shows coverage report for all tested files
|
|
```
|
|
|
|
## Troubleshooting & Maintenance
|
|
|
|
### Frontend Not Updating
|
|
**Problem**: Changes to source files not appearing in browser
|
|
**Solution**:
|
|
```bash
|
|
# Full rebuild
|
|
rm -rf build
|
|
npm run build
|
|
|
|
# Kill old serve process and restart
|
|
pkill -9 -f "serve.*build"
|
|
npx serve -s build -l 3000 &
|
|
|
|
# Hard refresh browser: Ctrl+Shift+R (Windows/Linux) or Cmd+Shift+R (Mac)
|
|
# Clear browser cache manually in DevTools
|
|
```
|
|
|
|
### Database Connection Issues
|
|
**Problem**: "Failed to fetch players" error
|
|
**Solution**:
|
|
```bash
|
|
# Check if backend is running
|
|
pm2 list | grep deathwatch
|
|
|
|
# View backend logs
|
|
pm2 logs deathwatch-server --lines 100
|
|
|
|
# Check database connection
|
|
curl http://localhost:5000/api/players
|
|
|
|
# Verify MariaDB is running
|
|
systemctl status mariadb
|
|
# or
|
|
mysql -u root -p -e "SELECT 1;"
|
|
```
|
|
|
|
### Port Already in Use
|
|
**Problem**: "EADDRINUSE: address already in use :::3000"
|
|
**Solution**:
|
|
```bash
|
|
# Find process using port 3000
|
|
lsof -i :3000
|
|
# or
|
|
netstat -tulpn | grep 3000
|
|
|
|
# Kill the process
|
|
kill -9 <PID>
|
|
|
|
# Or use a different port
|
|
npx serve -s build -l 3001
|
|
```
|
|
|
|
### API CORS Errors
|
|
**Problem**: "Access to XMLHttpRequest blocked by CORS policy"
|
|
**Solution**: CORS is already configured in backend (database/server.js)
|
|
- Proxy is configured in package.json: `"proxy": "http://localhost:5000"`
|
|
- Requests to `/api/*` are automatically routed to backend
|
|
- If issues persist, check backend logs and CORS configuration
|
|
|
|
## Performance Optimization
|
|
|
|
### Frontend
|
|
- **Code Splitting**: React automatically chunks large components
|
|
- **CSS**: Tailwind purges unused classes in production
|
|
- **JS**: Webpack tree-shaking removes dead code
|
|
- **Assets**: Images optimized by build process
|
|
|
|
### Backend
|
|
- **Query Caching**: Rules and bestiary data cached in memory
|
|
- **Session Validation**: Simple token-based (can be improved)
|
|
- **Database Indexing**: Ensure proper indexes on player ID, session ID
|
|
|
|
### Monitoring
|
|
```bash
|
|
# Check memory usage
|
|
pm2 list
|
|
|
|
# Monitor in real-time
|
|
pm2 monit
|
|
|
|
# View detailed logs
|
|
pm2 logs
|
|
|
|
# Check response times
|
|
curl -w "@curl-format.txt" http://localhost:5000/api/players
|
|
```
|
|
|
|
## Security Considerations
|
|
|
|
### Authentication
|
|
- ✅ Session-based with session ID validation
|
|
- ✅ bcrypt password hashing
|
|
- ⚠️ Default password (1234) for testing - CHANGE IN PRODUCTION
|
|
- ⚠️ Simple token format - consider JWT
|
|
|
|
### Authorization
|
|
- ✅ GM role check for Player Management
|
|
- ✅ Session validation on API routes
|
|
- ⚠️ No rate limiting implemented
|
|
- ⚠️ No input validation/sanitization
|
|
|
|
### HTTPS
|
|
- ⚠️ Not enforced (add in production)
|
|
- Use reverse proxy (nginx) or cloud provider SSL
|
|
|
|
### Recommended Improvements
|
|
1. Remove hardcoded test password
|
|
2. Implement JWT tokens instead of session IDs
|
|
3. Add rate limiting middleware
|
|
4. Add input validation/sanitization
|
|
5. Enable HTTPS/SSL
|
|
6. Implement CSRF protection
|
|
7. Add request logging and monitoring
|
|
|
|
## Database
|
|
|
|
### Connection
|
|
- **Host**: localhost (configured in database/mariadb.js)
|
|
- **User**: configurable (default: root)
|
|
- **Database**: dwroller (or deathwatch)
|
|
- **Driver**: mysql2
|
|
|
|
### Main Tables
|
|
```sql
|
|
-- Players table
|
|
CREATE TABLE players (
|
|
id INT PRIMARY KEY AUTO_INCREMENT,
|
|
name VARCHAR(255) UNIQUE NOT NULL,
|
|
passwordHash VARCHAR(255) NOT NULL,
|
|
rp INT DEFAULT 0,
|
|
xp INT DEFAULT 0,
|
|
renown VARCHAR(50) DEFAULT 'None',
|
|
tabInfo JSON,
|
|
createdAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
-- Sessions table
|
|
CREATE TABLE sessions (
|
|
id VARCHAR(255) PRIMARY KEY,
|
|
playerName VARCHAR(255) NOT NULL,
|
|
createdAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
expiresAt TIMESTAMP
|
|
);
|
|
|
|
-- Weapons, Rules, Bestiary tables
|
|
-- (See database/mariadb.js for full schema)
|
|
```
|
|
|
|
### Backup & Restore
|
|
```bash
|
|
# Backup database
|
|
mysqldump -u root -p dwroller > backup.sql
|
|
|
|
# Restore database
|
|
mysql -u root -p dwroller < backup.sql
|
|
|
|
# Verify backup integrity
|
|
npm run backup-scripts/repair-skills.js
|
|
```
|
|
|
|
## Development Workflow
|
|
|
|
### Making Changes
|
|
1. Create feature branch: `git checkout -b feature/my-feature`
|
|
2. Make code changes
|
|
3. Test locally: `npm start` and manual testing
|
|
4. Run tests: `npm run test:unit`
|
|
5. Build for production: `npm run build`
|
|
6. Commit and push
|
|
7. Deploy: Follow deployment process above
|
|
|
|
### Code Style
|
|
- ESLint configuration in eslintConfig (package.json)
|
|
- Tailwind CSS for styling (not inline styles)
|
|
- React hooks for state management (not class components)
|
|
- Functional components preferred
|
|
|
|
### Git Workflow
|
|
```bash
|
|
# View changes
|
|
git status
|
|
git diff
|
|
|
|
# Commit changes
|
|
git add .
|
|
git commit -m "Fix opacity issues in UI"
|
|
|
|
# Push to branch
|
|
git push origin clean-main
|
|
|
|
# Check current branch
|
|
git branch -a
|
|
```
|
|
|
|
## Environment Variables (if needed)
|
|
Create `.env` file in project root:
|
|
```
|
|
REACT_APP_API_URL=http://localhost:5000
|
|
REACT_APP_DEBUG=false
|
|
```
|
|
|
|
Access in React:
|
|
```javascript
|
|
const apiUrl = process.env.REACT_APP_API_URL;
|
|
```
|
|
|
|
## Monitoring & Logs
|
|
|
|
### Frontend Logs
|
|
```bash
|
|
# Browser console (DevTools F12)
|
|
- Network tab: Check API calls and response times
|
|
- Console tab: Check for JavaScript errors
|
|
- Application tab: Inspect stored data (localStorage)
|
|
```
|
|
|
|
### Backend Logs
|
|
```bash
|
|
# Real-time logs
|
|
pm2 logs deathwatch-server
|
|
|
|
# Last 100 lines
|
|
pm2 logs deathwatch-server --lines 100
|
|
|
|
# Specific error log
|
|
pm2 logs deathwatch-server --err
|
|
|
|
# Stream logs to file
|
|
pm2 logs deathwatch-server > logs.txt
|
|
```
|
|
|
|
## Common Workflows
|
|
|
|
### Deploy a Hotfix
|
|
```bash
|
|
git checkout clean-main
|
|
git pull origin clean-main
|
|
# Make fixes to source files
|
|
npm run build
|
|
pkill -9 -f "serve.*build"
|
|
npx serve -s build -l 3000 &
|
|
# Test in browser
|
|
```
|
|
|
|
### Rollback to Previous Build
|
|
```bash
|
|
# Keep previous build in backup
|
|
mv build build.backup
|
|
git checkout previous-commit
|
|
npm run build
|
|
npx serve -s build -l 3000 &
|
|
```
|
|
|
|
### Scale Frontend to Multiple Instances
|
|
```bash
|
|
# Instead of single serve process, use PM2 with clustering
|
|
pm2 start "npx serve -s build -l 3000" --name dwroller-frontend-1
|
|
pm2 start "npx serve -s build -l 3001" --name dwroller-frontend-2
|
|
pm2 start "npx serve -s build -l 3002" --name dwroller-frontend-3
|
|
|
|
# Load balance with nginx
|
|
# (Configure nginx upstream to round-robin across ports)
|
|
```
|
|
|
|
## References & Documentation
|
|
|
|
### Official Docs
|
|
- [Create React App](https://create-react-app.dev/)
|
|
- [React Documentation](https://react.dev/)
|
|
- [Tailwind CSS](https://tailwindcss.com/)
|
|
- [Express.js](https://expressjs.com/)
|
|
- [Jest Testing](https://jestjs.io/)
|
|
- [PM2 Documentation](https://pm2.keymetrics.io/)
|
|
|
|
### Project Files
|
|
- Backend routes: `database/server.js`
|
|
- Database connection: `database/mariadb.js`
|
|
- Authentication: `database/sessionModel.js`
|
|
- Middleware: `database/requireSession.js`
|
|
|
|
---
|
|
|
|
**Last Updated**: December 11, 2025
|
|
**Branch**: clean-main
|
|
**Status**: ✅ Production Ready
|