Yaltopia-Ticket-Admin/dev-docs/DEVELOPMENT.md

295 lines
6.0 KiB
Markdown

# Development Guide
Complete guide for developing the Yaltopia Ticket Admin application.
## Tech Stack
- **Frontend**: React 18 + TypeScript + Vite
- **UI**: TailwindCSS + shadcn/ui
- **State**: React Query (TanStack Query)
- **Routing**: React Router v6
- **HTTP Client**: Axios
- **Forms**: React Hook Form + Zod
- **Charts**: Recharts
- **Notifications**: Sonner
- **Error Tracking**: Sentry
- **Testing**: Vitest + Testing Library
## Quick Start
```bash
# Install dependencies
npm install
# Set up environment
cp .env.example .env
# Edit .env with your backend URL
# Start development server
npm run dev
# Run tests
npm run test
# Build for production
npm run build
```
## Project Structure
```
src/
├── components/ # Reusable UI components
├── pages/ # Page components
├── services/ # API service layer
│ ├── api/
│ │ └── client.ts # Axios instance
│ ├── auth.service.ts
│ ├── user.service.ts
│ └── ...
├── layouts/ # Layout components
├── lib/ # Utilities
└── test/ # Test utilities
```
## API Architecture
### Service Layer Pattern
All API calls go through typed service classes:
```
Component → Service → API Client → Backend
```
### Available Services
```typescript
import {
authService, // Authentication
userService, // User management
analyticsService, // Analytics
securityService, // Security
systemService, // System health
announcementService,// Announcements
auditService, // Audit logs
settingsService // Settings
} from '@/services'
```
### Usage Examples
**Fetching Data:**
```typescript
import { useQuery } from '@tanstack/react-query'
import { userService } from '@/services'
const { data, isLoading } = useQuery({
queryKey: ['users'],
queryFn: () => userService.getUsers({ page: 1, limit: 20 })
})
```
**Mutations:**
```typescript
import { useMutation, useQueryClient } from '@tanstack/react-query'
import { userService } from '@/services'
const queryClient = useQueryClient()
const mutation = useMutation({
mutationFn: (id: string) => userService.deleteUser(id),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['users'] })
toast.success('User deleted')
}
})
```
**Direct Calls:**
```typescript
import { authService } from '@/services'
const response = await authService.login({ email, password })
```
## Authentication
### Setup
1. Backend must return tokens on login
2. Frontend stores in httpOnly cookies (recommended) or localStorage
3. All requests automatically include auth token
4. 401 errors trigger automatic token refresh
### Login Flow
```typescript
// User logs in
const response = await authService.login({ email, password })
// Token stored automatically
// User redirected to dashboard
// All subsequent requests include token
await userService.getUsers() // Token added automatically
```
### Protected Routes
```typescript
<Route element={<ProtectedRoute />}>
<Route path="/admin/*" element={<AdminLayout />} />
</Route>
```
### Logout
```typescript
await authService.logout() // Clears tokens & cookies
navigate('/login')
```
## API Standards
### Service Methods
All service methods:
- Return typed data (no `response.data` unwrapping needed)
- Throw errors with `error.response.data.message`
- Use consistent naming (get, create, update, delete)
### Error Handling
```typescript
try {
await userService.deleteUser(id)
toast.success('User deleted')
} catch (error: any) {
toast.error(error.response?.data?.message || 'Operation failed')
}
```
### Type Safety
```typescript
// All responses are typed
const users: PaginatedResponse<User> = await userService.getUsers()
const stats: OverviewStats = await analyticsService.getOverview()
```
## Environment Variables
```bash
# Required
VITE_BACKEND_API_URL=http://localhost:3001/api/v1
# Optional (Sentry)
VITE_SENTRY_DSN=your-sentry-dsn
VITE_SENTRY_ENVIRONMENT=development
```
## Common Tasks
### Adding a New Service Method
```typescript
// src/services/user.service.ts
async exportUserData(userId: string): Promise<Blob> {
const response = await apiClient.get(`/admin/users/${userId}/export`, {
responseType: 'blob'
})
return response.data
}
```
### Adding a New Page
1. Create page component in `src/pages/`
2. Add route in `src/App.tsx`
3. Import required services
4. Use React Query for data fetching
### Adding a New Component
1. Create in `src/components/`
2. Use TypeScript for props
3. Follow existing patterns
4. Add to component exports if reusable
## Best Practices
### React Query
```typescript
// Good - specific query keys
queryKey: ['users', page, limit, search]
// Bad - too generic
queryKey: ['data']
```
### Service Layer
```typescript
// Good - use services
import { userService } from '@/services'
await userService.getUsers()
// Bad - direct axios
import axios from 'axios'
await axios.get('/api/users')
```
### Error Handling
```typescript
// Good - handle errors
try {
await userService.deleteUser(id)
} catch (error: any) {
toast.error(error.response?.data?.message)
}
// Bad - no error handling
await userService.deleteUser(id)
```
### Type Safety
```typescript
// Good - use types
const users: PaginatedResponse<User> = await userService.getUsers()
// Bad - any type
const users: any = await userService.getUsers()
```
## Troubleshooting
### CORS Errors
- Ensure backend has CORS configured
- Check `withCredentials: true` in API client
- Verify `VITE_BACKEND_API_URL` is correct
### 401 Errors
- Check token is being sent
- Verify backend token validation
- Check token expiration
### Build Errors
- Run `npm run build` to check TypeScript errors
- Fix any type errors
- Ensure all imports are correct
### Test Failures
- Run `npm run test` to see failures
- Check mock implementations
- Verify test data matches types
## Additional Resources
- [Testing Guide](./TESTING.md)
- [Deployment Guide](./DEPLOYMENT.md)
- [Security Guide](./SECURITY.md)
- [Troubleshooting](./TROUBLESHOOTING.md)