# 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)
