inital
This commit is contained in:
828
DEVELOPMENT.md
Normal file
828
DEVELOPMENT.md
Normal file
@@ -0,0 +1,828 @@
|
||||
# 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!
|
||||
Reference in New Issue
Block a user