829 lines
18 KiB
Markdown
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!
|