# 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 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 => { 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 ( Your Feature ); }; 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 } /> ``` ## 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(); 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 # 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!