540 lines
13 KiB
Markdown
540 lines
13 KiB
Markdown
# Development & Architecture Guide
|
|
|
|
## Project Structure Overview
|
|
|
|
```
|
|
aws-final-project/
|
|
├── backend/ # FastAPI Python application
|
|
├── frontend/ # React Vite SPA
|
|
├── helm/dating-app/ # Kubernetes Helm chart
|
|
├── docker-compose.yml # Local dev environment
|
|
├── README.md # Main documentation
|
|
├── DEPLOYMENT.md # Deployment instructions
|
|
└── DEVELOPMENT.md # This file
|
|
```
|
|
|
|
## Backend Architecture
|
|
|
|
### Core Components
|
|
|
|
**app/db.py** - Database Connection
|
|
- SimpleConnectionPool for connection management
|
|
- Auto-initialization of tables on startup
|
|
- Safe context manager for connections
|
|
|
|
**app/config.py** - Configuration Management
|
|
- Environment variable loading with defaults
|
|
- Settings validation
|
|
- Centralized config source
|
|
|
|
**app/auth/** - Authentication
|
|
- `utils.py`: Password hashing (bcrypt), JWT creation/validation
|
|
- `__init__.py`: Authorization dependency for FastAPI
|
|
|
|
**app/models/** - Database Models
|
|
- Pure Python classes representing database entities
|
|
- User, Profile, Photo, Like, Conversation, Message
|
|
- to_dict() methods for serialization
|
|
|
|
**app/schemas/** - Pydantic Schemas
|
|
- Request/response validation
|
|
- Type hints and documentation
|
|
- Automatic OpenAPI schema generation
|
|
|
|
**app/services/** - Business Logic
|
|
- `auth_service.py`: Registration, login
|
|
- `profile_service.py`: Profile CRUD, discovery
|
|
- `photo_service.py`: Upload, storage, deletion
|
|
- `like_service.py`: Like tracking, match detection
|
|
- `chat_service.py`: Message operations, conversations
|
|
|
|
**app/routers/** - API Endpoints
|
|
- Modular organization by feature
|
|
- Protected endpoints with `get_current_user` dependency
|
|
- Consistent error handling
|
|
|
|
### Database Design
|
|
|
|
#### users table
|
|
```sql
|
|
id (PK), email (UNIQUE), hashed_password, created_at, updated_at
|
|
```
|
|
|
|
#### profiles table
|
|
```sql
|
|
id (PK), user_id (FK UNIQUE), display_name, age, gender,
|
|
location, bio, interests (JSONB), created_at, updated_at
|
|
```
|
|
|
|
#### photos table
|
|
```sql
|
|
id (PK), profile_id (FK), file_path, display_order, created_at
|
|
```
|
|
|
|
#### likes table
|
|
```sql
|
|
id (PK), liker_id (FK), liked_id (FK), created_at
|
|
UNIQUE(liker_id, liked_id)
|
|
```
|
|
|
|
#### conversations table
|
|
```sql
|
|
id (PK), user_id_1 (FK), user_id_2 (FK), created_at, updated_at
|
|
UNIQUE(user_id_1, user_id_2)
|
|
```
|
|
|
|
#### messages table
|
|
```sql
|
|
id (PK), conversation_id (FK), sender_id (FK), content, created_at
|
|
```
|
|
|
|
### Key Design Decisions
|
|
|
|
1. **Synchronous psycopg2** - Per requirements, enables simpler debugging
|
|
2. **Connection Pooling** - SimpleConnectionPool provides basic pooling
|
|
3. **Auto-initialization** - Tables created on startup, no separate migration step
|
|
4. **JWT Tokens** - Stateless auth, no session storage needed
|
|
5. **Local File Storage** - Disk-based for lab, easily swappable to S3
|
|
6. **Match Logic** - Dual-directional like check in database
|
|
|
|
### Adding New Features
|
|
|
|
**Example: Add "message read receipts"**
|
|
|
|
1. Add schema to `app/schemas/message.py`:
|
|
```python
|
|
class MessageResponse(BaseModel):
|
|
# ... existing fields ...
|
|
read_at: Optional[str] = None
|
|
```
|
|
|
|
2. Update database in `app/db.py`:
|
|
```python
|
|
cur.execute("""
|
|
ALTER TABLE messages ADD COLUMN read_at TIMESTAMP
|
|
""")
|
|
```
|
|
|
|
3. Add method to `app/services/chat_service.py`:
|
|
```python
|
|
@staticmethod
|
|
def mark_message_read(message_id: int):
|
|
# Implementation
|
|
```
|
|
|
|
4. Add endpoint to `app/routers/chat.py`:
|
|
```python
|
|
@router.patch("/messages/{message_id}/read")
|
|
def mark_read(message_id: int, current_user: dict = Depends(get_current_user)):
|
|
# Implementation
|
|
```
|
|
|
|
## Frontend Architecture
|
|
|
|
### Project Structure
|
|
|
|
```
|
|
frontend/src/
|
|
├── pages/ # Full page components
|
|
│ ├── Login.jsx
|
|
│ ├── Register.jsx
|
|
│ ├── ProfileEditor.jsx
|
|
│ ├── Discover.jsx
|
|
│ ├── Matches.jsx
|
|
│ └── Chat.jsx
|
|
├── styles/ # CSS for each page
|
|
│ ├── auth.css
|
|
│ ├── profileEditor.css
|
|
│ ├── discover.css
|
|
│ ├── matches.css
|
|
│ └── chat.css
|
|
├── api.js # Centralized API client
|
|
├── App.jsx # Main app component
|
|
├── App.css # Global styles
|
|
├── main.jsx # React entry point
|
|
└── index.css # Global CSS
|
|
```
|
|
|
|
### API Client Pattern
|
|
|
|
**src/api.js** provides:
|
|
- Axios instance with base configuration
|
|
- Request interceptor for JWT token injection
|
|
- Response interceptor for 401 handling
|
|
- Organized API methods by feature:
|
|
- authAPI.register(), authAPI.login()
|
|
- profileAPI.getMyProfile(), profileAPI.discoverProfiles()
|
|
- etc.
|
|
|
|
**Usage in components:**
|
|
```javascript
|
|
import { profileAPI } from '../api'
|
|
|
|
const response = await profileAPI.getMyProfile()
|
|
const profiles = await profileAPI.discoverProfiles()
|
|
```
|
|
|
|
### State Management
|
|
|
|
**Simple localStorage approach:**
|
|
- JWT stored in localStorage, auto-attached to requests
|
|
- User ID stored for context
|
|
- Component-level state with useState for forms
|
|
- No Redux/MobX needed for MVP
|
|
|
|
**Example:**
|
|
```javascript
|
|
// After login
|
|
localStorage.setItem('token', response.data.access_token)
|
|
localStorage.setItem('user_id', response.data.user_id)
|
|
|
|
// On API calls
|
|
// Automatically added by axios interceptor
|
|
Authorization: `Bearer ${token}`
|
|
|
|
// On logout
|
|
localStorage.removeItem('token')
|
|
localStorage.removeItem('user_id')
|
|
```
|
|
|
|
### Component Patterns
|
|
|
|
**Page Component Template:**
|
|
```jsx
|
|
export default function FeaturePage() {
|
|
const [data, setData] = useState([])
|
|
const [isLoading, setIsLoading] = useState(false)
|
|
const [error, setError] = useState('')
|
|
|
|
useEffect(() => {
|
|
loadData()
|
|
}, [])
|
|
|
|
const loadData = async () => {
|
|
try {
|
|
setIsLoading(true)
|
|
const response = await featureAPI.getData()
|
|
setData(response.data)
|
|
} catch (err) {
|
|
setError(err.response?.data?.detail || 'Error')
|
|
} finally {
|
|
setIsLoading(false)
|
|
}
|
|
}
|
|
|
|
return (
|
|
<div className="feature-page">
|
|
{error && <div className="error-message">{error}</div>}
|
|
{/* JSX */}
|
|
</div>
|
|
)
|
|
}
|
|
```
|
|
|
|
### Styling Approach
|
|
|
|
- CSS modules for component isolation
|
|
- Global styles in index.css and App.css
|
|
- BEM naming convention for clarity
|
|
- Mobile-responsive with flexbox/grid
|
|
|
|
### Environment Configuration
|
|
|
|
Frontend uses Vite's import.meta.env:
|
|
|
|
```javascript
|
|
// In src/api.js
|
|
const API_BASE_URL = import.meta.env.VITE_API_URL || 'http://localhost:8000'
|
|
```
|
|
|
|
In `frontend/.env`:
|
|
```
|
|
VITE_API_URL=http://localhost:8000
|
|
```
|
|
|
|
## Docker Build Process
|
|
|
|
### Backend Dockerfile
|
|
|
|
```dockerfile
|
|
# Multi-stage not needed
|
|
# Single stage with Python 3.11
|
|
# System dependencies: gcc, postgresql-client
|
|
# Python dependencies: fastapi, uvicorn, etc.
|
|
# Health check via /health endpoint
|
|
# CMD: uvicorn main:app
|
|
```
|
|
|
|
### Frontend Dockerfile
|
|
|
|
```dockerfile
|
|
# Multi-stage: builder + runtime
|
|
# Stage 1: Build with Node
|
|
# - npm install
|
|
# - npm run build -> dist/
|
|
# Stage 2: Runtime with nginx
|
|
# - nginx:alpine
|
|
# - Copy dist to /usr/share/nginx/html
|
|
# - Custom nginx.conf for SPA routing
|
|
# - Health check via /health endpoint
|
|
```
|
|
|
|
### Nginx Configuration
|
|
|
|
Handles:
|
|
- SPA routing: try_files fallback to index.html
|
|
- Static file caching: 1-year expiry for assets
|
|
- Deny access to hidden files
|
|
- Health check endpoint
|
|
|
|
## Kubernetes Deployment
|
|
|
|
### Helm Chart Structure
|
|
|
|
**Chart.yaml** - Chart metadata
|
|
|
|
**values.yaml** - Default configuration (override for different environments)
|
|
|
|
**values-lab.yaml** - Home-lab specific values
|
|
- Single replicas
|
|
- Local storage classes
|
|
- Default passwords (change in production)
|
|
|
|
**values-aws.yaml** - AWS specific values
|
|
- Multiple replicas
|
|
- EBS storage class
|
|
- ALB ingress class
|
|
- RDS database URL
|
|
|
|
**Templates:**
|
|
- `namespace.yaml` - Creates dedicated namespace
|
|
- `configmap.yaml` - Backend and frontend config
|
|
- `secret.yaml` - PostgreSQL credentials
|
|
- `postgres.yaml` - PostgreSQL deployment + PVC + service
|
|
- `backend.yaml` - Backend deployment + service
|
|
- `frontend.yaml` - Frontend deployment + service
|
|
- `ingress.yaml` - Ingress for both services
|
|
|
|
### Deployment Flow
|
|
|
|
1. Helm reads values file
|
|
2. Templates rendered with values
|
|
3. Kubernetes resources created in order:
|
|
- Namespace
|
|
- ConfigMap, Secret
|
|
- PVC
|
|
- Postgres deployment waits for PVC
|
|
- Backend deployment waits for postgres
|
|
- Frontend deployment (no deps)
|
|
- Services for each
|
|
- Ingress routes traffic
|
|
|
|
### Network Architecture
|
|
|
|
```
|
|
Internet
|
|
|
|
|
Ingress (nginx/traefik)
|
|
|
|
|
+-> Frontend Service (80) -> Frontend Pods
|
|
|
|
|
+-> Backend Service (8000) -> Backend Pods
|
|
|
|
|
Postgres Service (5432)
|
|
|
|
|
Postgres Pod
|
|
```
|
|
|
|
### Storage
|
|
|
|
**PVC for Postgres:**
|
|
- ReadWriteOnce access mode
|
|
- Survives pod restarts
|
|
- Data persists across deployments
|
|
|
|
**PVC for Backend Media:**
|
|
- ReadWriteMany access mode (for multiple replicas)
|
|
- Shared media storage across pods
|
|
- Migrates to S3 for cloud deployments
|
|
|
|
## Development Workflow
|
|
|
|
### Local Testing
|
|
|
|
```bash
|
|
# 1. Modify code
|
|
# 2. Test with compose
|
|
docker-compose up -d
|
|
curl http://localhost:8000/docs
|
|
|
|
# 3. Modify Helm values
|
|
# 4. Test with Helm (dry-run)
|
|
helm install dating-app ./helm/dating-app \
|
|
-n dating-app --dry-run --debug
|
|
|
|
# 5. Test with Helm (actual)
|
|
helm install dating-app ./helm/dating-app \
|
|
-n dating-app --create-namespace
|
|
|
|
# 6. Verify
|
|
kubectl get all -n dating-app
|
|
```
|
|
|
|
### Code Changes
|
|
|
|
**Backend changes:**
|
|
- Edit Python files in app/
|
|
- Changes automatically available in dev environment
|
|
- Production requires rebuilding Docker image
|
|
|
|
**Frontend changes:**
|
|
- Edit .jsx files
|
|
- Changes automatically available in dev environment
|
|
- Production requires rebuilding and redeploying
|
|
|
|
**Database schema changes:**
|
|
- Modify app/db.py init_db()
|
|
- For Alembic (future): `alembic revision --autogenerate`
|
|
- Existing migrations: Update manually or recreate database
|
|
|
|
## Performance Considerations
|
|
|
|
### Backend
|
|
|
|
- Connection pooling limits: Currently 1-20 connections
|
|
- Query optimization: Use indexes on foreign keys
|
|
- Response caching: Can add for discover endpoint
|
|
- Pagination: Not implemented yet, add for large datasets
|
|
|
|
### Frontend
|
|
|
|
- Image optimization: Profile pictures should be compressed
|
|
- Lazy loading: Add for discover card images
|
|
- Code splitting: Can split by route
|
|
- Caching: Service workers for offline support
|
|
|
|
### Database
|
|
|
|
- Indexes created on common query columns
|
|
- JSONB for interests enables efficient queries
|
|
- Unique constraints prevent duplicates
|
|
- Foreign keys maintain referential integrity
|
|
|
|
## Testing Strategy
|
|
|
|
### Unit Tests (Future)
|
|
```python
|
|
# backend/tests/
|
|
# test_auth.py - Auth functions
|
|
# test_services.py - Service logic
|
|
# test_routers.py - API endpoints
|
|
```
|
|
|
|
### Integration Tests (Future)
|
|
```python
|
|
# Full workflow testing
|
|
# Database interactions
|
|
# API contract validation
|
|
```
|
|
|
|
### E2E Tests (Future)
|
|
```javascript
|
|
# frontend/tests/
|
|
# User registration flow
|
|
# Profile creation
|
|
# Swiping and matching
|
|
# Chat functionality
|
|
```
|
|
|
|
### Manual Testing Checklist
|
|
|
|
- [ ] Registration with new email
|
|
- [ ] Login with correct password
|
|
- [ ] Create and update profile
|
|
- [ ] Upload multiple photos
|
|
- [ ] Delete photos
|
|
- [ ] View discover profiles
|
|
- [ ] Like a user
|
|
- [ ] Check matches
|
|
- [ ] Send message to match
|
|
- [ ] View conversation history
|
|
- [ ] Logout
|
|
|
|
## Security Considerations
|
|
|
|
### Current Implementation
|
|
- ✅ Password hashing with bcrypt
|
|
- ✅ JWT with expiration
|
|
- ✅ CORS configured
|
|
- ✅ Protected endpoints
|
|
- ✅ SQL injection prevention (parameterized queries)
|
|
|
|
### Recommended Additions
|
|
- [ ] Rate limiting on auth endpoints
|
|
- [ ] HTTPS/TLS enforcement
|
|
- [ ] CSRF token for state-changing operations
|
|
- [ ] Input validation and sanitization
|
|
- [ ] Audit logging
|
|
- [ ] API key authentication for service-to-service
|
|
- [ ] Secrets management (Vault)
|
|
- [ ] Regular security scanning
|
|
- [ ] Penetration testing
|
|
|
|
### Data Protection
|
|
- [ ] Encrypt sensitive data in transit (HTTPS)
|
|
- [ ] Encrypt sensitive data at rest
|
|
- [ ] Implement data retention policies
|
|
- [ ] GDPR compliance (right to delete, data export)
|
|
- [ ] Regular backups with encryption
|
|
- [ ] Secure backup storage
|
|
|
|
## Common Issues & Solutions
|
|
|
|
### Issue: Photo uploads fail
|
|
**Cause:** Media directory not writable
|
|
**Solution:** Check MEDIA_DIR permissions, ensure PVC mounted
|
|
|
|
### Issue: Matches not showing
|
|
**Cause:** Mutual like check query fails
|
|
**Solution:** Verify both users liked each other, check database
|
|
|
|
### Issue: Slow profile discovery
|
|
**Cause:** N+1 query problem
|
|
**Solution:** Add query optimization, batch load photos
|
|
|
|
### Issue: Connection pool exhausted
|
|
**Cause:** Too many concurrent requests
|
|
**Solution:** Increase pool size, add connection timeout
|
|
|
|
## Future Enhancements
|
|
|
|
1. **WebSocket Chat**
|
|
- Real-time messages without polling
|
|
- Typing indicators
|
|
- Read receipts
|
|
|
|
2. **Image Optimization**
|
|
- Automatic compression
|
|
- Multiple sizes for responsive design
|
|
- CDN distribution
|
|
|
|
3. **Recommendation Engine**
|
|
- Machine learning for match suggestions
|
|
- Interest-based filtering
|
|
- Location-based matching
|
|
|
|
4. **Advanced Features**
|
|
- Video calls
|
|
- Story features
|
|
- Search and filtering
|
|
- Blocking/reporting
|
|
- Verification badges
|
|
|
|
5. **Infrastructure**
|
|
- Load balancing improvements
|
|
- Caching layer (Redis)
|
|
- Message queue (RabbitMQ) for async tasks
|
|
- Monitoring and alerting
|
|
- CI/CD pipeline
|
|
- Database read replicas
|