Files
dwroller/DEVELOPMENT_GUIDE.md

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