Files
dashboard/DEVELOPMENT.md
Matthias Hochmeister f09748f4a1 inital
2026-02-23 17:08:58 +01:00

829 lines
18 KiB
Markdown

# Development Guide
Welcome to the Feuerwehr Dashboard development guide. This document will help you get started with developing, testing, and contributing to the project.
## Table of Contents
- [Developer Onboarding](#developer-onboarding)
- [Local Development Setup](#local-development-setup)
- [Project Structure](#project-structure)
- [Code Architecture](#code-architecture)
- [Development Workflow](#development-workflow)
- [Adding New Features](#adding-new-features)
- [Testing Guidelines](#testing-guidelines)
- [Debugging](#debugging)
- [Common Issues](#common-issues)
- [Best Practices](#best-practices)
## Developer Onboarding
### Prerequisites
Before you begin, ensure you have:
- **Node.js 18+** - [Download](https://nodejs.org/)
- **Docker Desktop** - [Download](https://www.docker.com/products/docker-desktop)
- **Git** - [Download](https://git-scm.com/)
- **Code Editor** - VS Code recommended
- **Authentik Access** - For testing authentication
### Recommended VS Code Extensions
```json
{
"recommendations": [
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode",
"ms-vscode.vscode-typescript-next",
"bradlc.vscode-tailwindcss",
"ms-azuretools.vscode-docker",
"prisma.prisma"
]
}
```
### First Steps
1. **Clone the repository**:
```bash
git clone <repository-url>
cd feuerwehr_dashboard
```
2. **Read the documentation**:
- [README.md](README.md) - Project overview
- [ARCHITECTURE.md](ARCHITECTURE.md) - System design
- [API_DOCUMENTATION.md](API_DOCUMENTATION.md) - API reference
3. **Set up your environment** (see below)
4. **Run the application** locally
5. **Make a small change** to familiarize yourself with the codebase
## Local Development Setup
### Option 1: Docker-Based Development (Recommended for Beginners)
Start the development database:
```bash
make dev
```
This starts only PostgreSQL, allowing you to run backend/frontend locally with hot reload.
### Option 2: Fully Dockerized (Quick Testing)
Run everything in Docker:
```bash
make prod
```
Note: This doesn't support hot reload, so it's less ideal for active development.
### Option 3: Native Development (Full Control)
#### Step 1: Start Database
```bash
make dev
```
Or manually:
```bash
docker-compose -f docker-compose.dev.yml up -d
```
#### Step 2: Configure Backend
Create `backend/.env`:
```bash
cd backend
cat > .env << EOF
DATABASE_URL=postgresql://dev_user:dev_password@localhost:5432/feuerwehr_dev
JWT_SECRET=dev_secret_do_not_use_in_production
NODE_ENV=development
PORT=3000
LOG_LEVEL=debug
# Authentik - use your dev instance
AUTHENTIK_CLIENT_ID=your_dev_client_id
AUTHENTIK_CLIENT_SECRET=your_dev_client_secret
AUTHENTIK_ISSUER=http://localhost:9000/application/o/feuerwehr/
AUTHENTIK_REDIRECT_URI=http://localhost:5173/auth/callback
EOF
```
#### Step 3: Install Backend Dependencies
```bash
cd backend
npm install
```
#### Step 4: Run Backend
```bash
npm run dev
```
Backend will start on `http://localhost:3000` with auto-reload on file changes.
#### Step 5: Configure Frontend
Create `frontend/.env`:
```bash
cd frontend
cat > .env << EOF
VITE_API_URL=http://localhost:3000
EOF
```
#### Step 6: Install Frontend Dependencies
```bash
cd frontend
npm install
```
#### Step 7: Run Frontend
```bash
npm run dev
```
Frontend will start on `http://localhost:5173` with hot module replacement.
### Verify Setup
Test backend:
```bash
curl http://localhost:3000/health
# Should return: {"status":"ok","timestamp":"..."}
```
Test frontend:
```bash
open http://localhost:5173
# Browser should open with login page
```
## Project Structure
### Backend Structure
```
backend/
├── src/
│ ├── config/ # Configuration files
│ │ ├── database.ts # Database connection and pool
│ │ ├── environment.ts # Environment variables
│ │ └── oauth.ts # OAuth/Authentik configuration
│ ├── controllers/ # Request handlers
│ │ ├── auth.controller.ts
│ │ └── user.controller.ts
│ ├── database/
│ │ └── migrations/ # SQL migration files
│ │ ├── 001_create_users_table.sql
│ │ └── 002_create_sessions_table.sql
│ ├── middleware/ # Express middleware
│ │ ├── auth.middleware.ts # Authentication
│ │ ├── error.middleware.ts # Error handling
│ │ └── rate-limit.middleware.ts # Rate limiting
│ ├── models/ # Data models
│ │ └── user.model.ts
│ ├── routes/ # API routes
│ │ ├── auth.routes.ts
│ │ └── user.routes.ts
│ ├── services/ # Business logic
│ │ ├── auth.service.ts
│ │ ├── oauth.service.ts
│ │ ├── token.service.ts
│ │ └── user.service.ts
│ ├── types/ # TypeScript types
│ │ ├── auth.types.ts
│ │ └── user.types.ts
│ ├── utils/ # Utility functions
│ │ └── logger.ts
│ ├── app.ts # Express app configuration
│ └── server.ts # Server entry point
├── logs/ # Application logs (gitignored)
├── Dockerfile
├── package.json
├── tsconfig.json
└── nodemon.json
```
### Frontend Structure
```
frontend/
├── src/
│ ├── components/ # Reusable React components
│ │ ├── common/ # Shared components
│ │ │ ├── Header.tsx
│ │ │ └── Loading.tsx
│ │ └── layout/ # Layout components
│ │ └── MainLayout.tsx
│ ├── contexts/ # React Context providers
│ │ └── AuthContext.tsx # Authentication state
│ ├── pages/ # Page components
│ │ ├── auth/
│ │ │ ├── LoginPage.tsx
│ │ │ └── CallbackPage.tsx
│ │ ├── dashboard/
│ │ │ └── DashboardPage.tsx
│ │ └── user/
│ │ └── ProfilePage.tsx
│ ├── services/ # API service layer
│ │ ├── api.ts # Axios instance
│ │ ├── authService.ts # Auth API calls
│ │ └── userService.ts # User API calls
│ ├── theme/ # MUI theme configuration
│ │ └── theme.ts
│ ├── types/ # TypeScript types
│ │ └── auth.types.ts
│ ├── utils/ # Utility functions
│ │ └── storage.ts # Local storage helpers
│ ├── App.tsx # Main app component
│ ├── main.tsx # Entry point
│ └── vite-env.d.ts # Vite type declarations
├── public/ # Static assets
├── nginx.conf # Production Nginx config
├── Dockerfile
├── package.json
├── vite.config.ts
└── tsconfig.json
```
## Code Architecture
### Backend Architecture
#### Layered Architecture
1. **Routes Layer** (`routes/`)
- Define API endpoints
- Input validation (Zod schemas)
- Route to controllers
2. **Controllers Layer** (`controllers/`)
- Handle HTTP requests/responses
- Call services for business logic
- Format responses
3. **Services Layer** (`services/`)
- Business logic implementation
- Database operations
- External API calls (OAuth)
4. **Models Layer** (`models/`)
- Data structures
- Database queries
- Data validation
5. **Middleware Layer** (`middleware/`)
- Authentication
- Error handling
- Rate limiting
- Logging
#### Request Flow
```
Client Request
Express Router (routes/)
Middleware (auth, validation)
Controller (controllers/)
Service (services/)
Model (models/)
Database
← Response flows back up
```
### Frontend Architecture
#### Component-Based Architecture
1. **Pages** - Route-level components
2. **Layouts** - Structural components (header, sidebar)
3. **Components** - Reusable UI elements
4. **Contexts** - Global state management
5. **Services** - API communication
#### Data Flow
```
User Interaction
Component Event Handler
Service Layer (API call)
Backend API
Update Context/State
Re-render Components
```
### Authentication Flow
```
1. User clicks "Login"
2. Frontend redirects to Authentik
3. User authenticates with Authentik
4. Authentik redirects to /auth/callback with code
5. Frontend sends code to backend /api/auth/callback
6. Backend exchanges code for tokens with Authentik
7. Backend creates user session in database
8. Backend returns JWT access/refresh tokens
9. Frontend stores tokens and updates AuthContext
10. User is redirected to dashboard
```
## Development Workflow
### 1. Create Feature Branch
```bash
git checkout -b feature/your-feature-name
# or
git checkout -b fix/bug-description
```
### 2. Make Changes
- Write code following style guidelines
- Add comments for complex logic
- Update types as needed
### 3. Test Locally
```bash
# Run backend tests
cd backend && npm test
# Run frontend tests
cd frontend && npm test
# Manual testing
# Test in browser at http://localhost:5173
```
### 4. Commit Changes
```bash
git add .
git commit -m "feat: add user profile editing feature"
```
Follow [Conventional Commits](https://www.conventionalcommits.org/):
- `feat:` - New feature
- `fix:` - Bug fix
- `docs:` - Documentation
- `refactor:` - Code refactoring
- `test:` - Adding tests
- `chore:` - Maintenance
### 5. Push and Create PR
```bash
git push origin feature/your-feature-name
```
Create pull request on your Git platform.
## Adding New Features
### Adding a New API Endpoint
#### Step 1: Define Types
Create or update `backend/src/types/your-feature.types.ts`:
```typescript
export interface YourFeature {
id: number;
name: string;
createdAt: Date;
}
export interface CreateYourFeatureDto {
name: string;
}
```
#### Step 2: Create Model
Create `backend/src/models/your-feature.model.ts`:
```typescript
import { pool } from '../config/database';
import { YourFeature } from '../types/your-feature.types';
export const createYourFeature = async (name: string): Promise<YourFeature> => {
const result = await pool.query(
'INSERT INTO your_features (name) VALUES ($1) RETURNING *',
[name]
);
return result.rows[0];
};
```
#### Step 3: Create Service
Create `backend/src/services/your-feature.service.ts`:
```typescript
import * as YourFeatureModel from '../models/your-feature.model';
import { CreateYourFeatureDto } from '../types/your-feature.types';
class YourFeatureService {
async create(dto: CreateYourFeatureDto) {
// Business logic here
return await YourFeatureModel.createYourFeature(dto.name);
}
}
export default new YourFeatureService();
```
#### Step 4: Create Controller
Create `backend/src/controllers/your-feature.controller.ts`:
```typescript
import { Request, Response } from 'express';
import yourFeatureService from '../services/your-feature.service';
class YourFeatureController {
async create(req: Request, res: Response) {
try {
const feature = await yourFeatureService.create(req.body);
res.status(201).json(feature);
} catch (error) {
res.status(500).json({ error: 'Failed to create feature' });
}
}
}
export default new YourFeatureController();
```
#### Step 5: Create Routes
Create `backend/src/routes/your-feature.routes.ts`:
```typescript
import { Router } from 'express';
import yourFeatureController from '../controllers/your-feature.controller';
import { authenticate } from '../middleware/auth.middleware';
const router = Router();
router.post('/', authenticate, yourFeatureController.create);
export default router;
```
#### Step 6: Register Routes
Update `backend/src/app.ts`:
```typescript
import yourFeatureRoutes from './routes/your-feature.routes';
app.use('/api/your-features', yourFeatureRoutes);
```
#### Step 7: Create Database Migration
Create `backend/src/database/migrations/00X_create_your_features_table.sql`:
```sql
CREATE TABLE IF NOT EXISTS your_features (
id SERIAL PRIMARY KEY,
name VARCHAR(255) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX idx_your_features_name ON your_features(name);
```
### Adding a New Frontend Page
#### Step 1: Create Page Component
Create `frontend/src/pages/your-feature/YourFeaturePage.tsx`:
```typescript
import React from 'react';
import { Container, Typography } from '@mui/material';
const YourFeaturePage: React.FC = () => {
return (
<Container>
<Typography variant="h4">Your Feature</Typography>
</Container>
);
};
export default YourFeaturePage;
```
#### Step 2: Create Service
Create `frontend/src/services/yourFeatureService.ts`:
```typescript
import api from './api';
export const createYourFeature = async (name: string) => {
const response = await api.post('/api/your-features', { name });
return response.data;
};
```
#### Step 3: Add Route
Update `frontend/src/App.tsx`:
```typescript
import YourFeaturePage from './pages/your-feature/YourFeaturePage';
// In your routes
<Route path="/your-feature" element={<YourFeaturePage />} />
```
## Testing Guidelines
### Backend Testing
Create `backend/src/__tests__/your-feature.test.ts`:
```typescript
import yourFeatureService from '../services/your-feature.service';
describe('YourFeatureService', () => {
test('should create feature', async () => {
const feature = await yourFeatureService.create({ name: 'Test' });
expect(feature.name).toBe('Test');
});
});
```
Run tests:
```bash
cd backend
npm test
```
### Frontend Testing
Create `frontend/src/__tests__/YourFeaturePage.test.tsx`:
```typescript
import { render, screen } from '@testing-library/react';
import YourFeaturePage from '../pages/your-feature/YourFeaturePage';
test('renders your feature page', () => {
render(<YourFeaturePage />);
expect(screen.getByText('Your Feature')).toBeInTheDocument();
});
```
Run tests:
```bash
cd frontend
npm test
```
### Manual Testing Checklist
- [ ] Feature works in development mode
- [ ] Feature works in production build
- [ ] Authenticated users can access
- [ ] Unauthorized access is blocked
- [ ] Error states are handled
- [ ] Loading states are shown
- [ ] Responsive on mobile
- [ ] Works in Chrome, Firefox, Safari
## Debugging
### Backend Debugging
#### VS Code Launch Configuration
Create `.vscode/launch.json`:
```json
{
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Debug Backend",
"runtimeExecutable": "npm",
"runtimeArgs": ["run", "dev"],
"cwd": "${workspaceFolder}/backend",
"console": "integratedTerminal"
}
]
}
```
#### Console Logging
```typescript
import logger from '../utils/logger';
logger.debug('Debug message', { data });
logger.info('Info message');
logger.warn('Warning message');
logger.error('Error message', { error });
```
#### Database Queries
Enable query logging in `backend/src/config/database.ts`:
```typescript
const pool = new Pool({
// ...config
log: (msg) => logger.debug(msg)
});
```
### Frontend Debugging
#### React DevTools
Install [React Developer Tools](https://react.dev/learn/react-developer-tools) browser extension.
#### Console Logging
```typescript
console.log('Data:', data);
console.error('Error:', error);
```
#### Network Tab
Use browser DevTools Network tab to inspect API calls.
#### State Debugging
```typescript
const [state, setState] = useState(initialState);
useEffect(() => {
console.log('State changed:', state);
}, [state]);
```
## Common Issues
### Database Connection Failed
**Problem**: Backend can't connect to database
**Solution**:
```bash
# Verify database is running
docker ps | grep postgres
# Restart database
docker-compose -f docker-compose.dev.yml restart
# Check logs
docker logs feuerwehr_db_dev
```
### Port Already in Use
**Problem**: Port 3000 or 5173 already occupied
**Solution**:
```bash
# Find process using port
lsof -i :3000
# Kill process
kill -9 <PID>
# Or change port in package.json
```
### TypeScript Errors
**Problem**: Type errors in VS Code
**Solution**:
```bash
# Restart TypeScript server in VS Code
# Cmd+Shift+P > "TypeScript: Restart TS Server"
# Rebuild
cd backend && npm run build
cd frontend && npm run build
```
### Authentik Redirect Fails
**Problem**: OAuth callback returns error
**Solution**:
1. Verify redirect URI exactly matches in Authentik
2. Check client ID and secret in `.env`
3. Ensure Authentik is accessible from browser
4. Check browser console for CORS errors
### Hot Reload Not Working
**Problem**: Changes don't reflect immediately
**Solution**:
```bash
# Backend - check nodemon is running
# Frontend - restart Vite dev server
npm run dev
```
## Best Practices
### Code Style
- Use TypeScript strict mode
- Follow ESLint rules
- Use Prettier for formatting
- Write descriptive variable names
- Add JSDoc comments for public APIs
### Security
- Never commit secrets to Git
- Validate all inputs
- Use parameterized queries
- Sanitize user input
- Keep dependencies updated
### Performance
- Use database indexes
- Implement pagination for lists
- Cache expensive operations
- Optimize bundle size
- Use React.memo for expensive components
### Git Workflow
- Keep commits small and focused
- Write clear commit messages
- Rebase before merging
- Delete branches after merge
- Don't commit `node_modules/` or `.env`
## Getting Help
- **Documentation**: Check all `.md` files
- **Code Comments**: Read inline documentation
- **Team Chat**: Ask in development channel
- **GitHub Issues**: Search existing issues
- **Stack Overflow**: Search for similar problems
## Next Steps
After completing setup:
1. Explore the codebase
2. Try adding a simple feature
3. Read [ARCHITECTURE.md](ARCHITECTURE.md)
4. Review [API_DOCUMENTATION.md](API_DOCUMENTATION.md)
5. Check [CONTRIBUTING.md](CONTRIBUTING.md)
Happy coding!