Files
dwroller/docs/developer-guide.md
alex a4cabbd2b8 Clean rules database and add documentation
- Remove OCR noise, credits, and duplicates from rules-database.json (288→255 rules)
- Add clean_rules.py script for rule cleanup
- Add CLAUDE.md, docs/, and update README with documentation links

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-22 17:35:36 +02:00

440 lines
7.9 KiB
Markdown

# Developer Guide
## Project Structure
```
dwroller/
├── backend/
│ ├── src/
│ │ ├── routes/ # API routes
│ │ ├── models/ # Data models
│ │ ├── controllers/ # Route controllers
│ │ ├── middleware/ # Auth, validation
│ │ └── utils/ # Helper functions
│ ├── server.js # Entry point
│ └── package.json
├── frontend/
│ ├── src/
│ │ ├── components/ # React components
│ │ ├── pages/ # Route pages
│ │ ├── hooks/ # Custom hooks
│ │ └── store/ # State management
│ ├── public/ # Static assets
│ ├── package.json
│ └── vite.config.js
├── data/ # Static data files
├── database/ # Database files
└── docs/ # Documentation
```
## Development Setup
### Backend
```bash
cd backend
npm install
npm run dev
```
The backend starts on port 5000.
### Frontend
```bash
cd frontend
npm install
npm run dev
```
The frontend starts on port 3000.
## Code Style
### JavaScript/TypeScript
- Use TypeScript for new code
- Follow Airbnb JavaScript style guide
- Maximum 100 character line length
- Use ESLint for linting
```typescript
// Example code style
interface Player {
id: number;
name: string;
xp: number;
rp: number;
}
export class PlayerService {
async getPlayer(id: number): Promise<Player> {
const player = await this.repository.findById(id);
return this.transform(player);
}
}
```
### React
- Functional components with hooks
- Use TypeScript for props
- Follow React best practices
- Use Context for global state
```typescript
// Example React component
interface ShopItemProps {
item: ShopItem;
onPurchase: (itemId: number) => void;
}
const ShopItem: React.FC<ShopItemProps> = ({ item, onPurchase }) => {
return (
<div className="shop-item">
<h3>{item.name}</h3>
<p>Cost: {item.cost} RP</p>
<button onClick={() => onPurchase(item.id)}>
Purchase
</button>
</div>
);
};
```
## Database
### Schema
The database uses SQLite by default. The schema is created automatically on first run.
Main tables:
- `players` - Player accounts
- `items` - Shop inventory
- `inventory` - Player item ownership
- `sessions` - Game session tracking
- `webhooks` - Webhook configurations
### Migrations
Migrations are stored in `backend/migrations/`.
```bash
# Run migrations
npm run migrate
# Create new migration
npx knex migrate:make create_new_table
```
## API Development
### Creating a New Endpoint
```bash
backend/src/routes/new-endpoints.ts
```
```typescript
import express, { Request, Response } from 'express';
const router = express.Router();
// GET /new-endpoint
router.get('/', async (req: Request, res: Response) => {
const data = await getNewData();
res.json({ success: true, data });
});
export default router;
```
Add to `server.js`:
```typescript
import newEndpoints from './src/routes/new-endpoints';
app.use('/api/new', newEndpoints);
```
### Adding Authentication
```typescript
import { requireAuth } from '../middleware/auth';
router.get(protectedRoute, requireAuth, async (req, res) => {
// Protected route logic
});
```
## Frontend Development
### Creating a New Component
```bash
frontend/src/components/NewComponent.tsx
```
```typescript
import React from 'react';
interface NewComponentProps {
data: any;
onAction: (action: string) => void;
}
export const NewComponent: React.FC<NewComponentProps> = ({
data,
onAction,
}) => {
const handleClick = () => {
onAction('click');
};
return <div className="new-component">{data.title}</div>;
};
```
### State Management
Use React Context for global state:
```typescript
// frontend/src/store/PlayerContext.tsx
import React, { createContext, useContext, useState } from 'react';
interface PlayerState {
players: Player[];
addPlayer: (player: Player) => void;
}
const PlayerContext = createContext<PlayerState | undefined>(undefined);
export const PlayerProvider: React.FC<{ children: React.ReactNode }> = ({
children,
}) => {
const [players, setPlayers] = useState<Player[]>([]);
const addPlayer = (player: Player) => {
setPlayers((prev) => [...prev, player]);
};
return (
<PlayerContext.Provider value={{ players, addPlayer }}>
{children}
</PlayerContext.Provider>
);
};
```
## Testing
### Backend Tests
```bash
backend/src/routes/__tests__/new-endpoints.test.ts
```
```typescript
import request from 'supertest';
import app from '../../../server';
describe('New Endpoint', () => {
it('should return 200 for GET', async () => {
const res = await request(app).get('/new-endpoint');
expect(res.statusCode).toBe(200);
expect(res.body.success).toBe(true);
});
});
```
Run tests:
```bash
npm test
```
### Frontend Tests
```bash
frontend/src/components/__tests__/NewComponent.test.tsx
```
```typescript
import { render, screen } from '@testing-library/react';
import NewComponent from '../NewComponent';
describe('NewComponent', () => {
it('renders the title', () => {
render(<NewComponent data={{ title: 'Test' }} />);
expect(screen.getByText('Test')).toBeInTheDocument();
});
});
```
Run tests:
```bash
npm test
```
## Debugging
### Backend Debugging
```bash
# Enable verbose logging
NODE_ENV=development npm run server
# View logs
tail -f backend.log
```
### Frontend Debugging
```bash
# Open DevTools
npm run dev
# Check browser console
# Network tab for API calls
```
## Deployment
### Build
```bash
# Build frontend
npm run build
# Build backend
cd backend
npm run build
```
### PM2 Setup
```bash
# Start with PM2
npm run pm2:start
# View logs
pm2 logs
# Stop
npm run pm2:stop
```
### Production Environment Variables
```bash
# Create production env
cp .env.example .env.production
# Set required variables:
# - NODE_ENV=production
# - SESSION_SECRET
# - X_GM_SECRET
# - PORT
```
## Performance
### Optimization Tips
1. **Database**: Use indexes for frequent queries
2. **Frontend**: Enable code splitting
3. **API**: Implement caching for static data
4. **Images**: Use lazy loading
### Caching
```typescript
// Example: Cache shop data
const CACHE_DURATION = 5 * 60 * 1000; // 5 minutes
async function getShop() {
const cached = getFromCache('shop');
if (cached) return cached;
const shop = await db.items.findAll();
setCache('shop', shop, CACHE_DURATION);
return shop;
}
```
## Security
### Authentication
All API endpoints use session-based authentication. Implement proper session management:
```typescript
// Session middleware
import { verifyToken } from '../utils/auth';
export const requireAuth = async (req: Request, res: Response, next: NextFunction) => {
const session = req.headers['cookie'];
if (!session) {
return res.status(401).json({ error: 'Unauthorized' });
}
try {
req.user = await verifyToken(session);
next();
} catch (error) {
return res.status(401).json({ error: 'Invalid session' });
}
};
```
### API Security
1. Use HTTPS in production
2. Rate limit API requests
3. Validate all inputs
4. Use prepared statements for SQL
5. Never expose sensitive data
## Contributing
### Pull Request Process
1. Fork the repository
2. Create a feature branch
3. Make your changes
4. Add tests for new functionality
5. Update documentation
6. Submit a pull request
### Code Review
All PRs will be reviewed for:
- Code quality
- Test coverage
- Documentation
- Security
- Performance
### Commit Messages
Use conventional commits:
```bash
feat: add new shop item filter
fix: resolve authentication issue
docs: update API documentation
chore: update dependencies
```
## Resources
- [React Documentation](https://react.dev/)
- [Express.js Documentation](https://expressjs.com/)
- [TypeScript Handbook](https://www.typescriptlang.org/docs/)
- [SQLite Documentation](https://www.sqlite.org/docs.html)