FitHub is built as a modern, scalable REST API using Django REST Framework with a focus on maintainability, testability, and deployment automation.
- Django REST Framework: Chosen for its mature ecosystem, built-in authentication, and excellent API tooling
- PostgreSQL: Selected for ACID compliance, JSON support, and excellent Django integration
- JWT Authentication: Primary authentication method for stateless API access
- uv Package Manager: Fast Python package manager for improved development experience
- Docker: Containerization for consistent deployment across environments
- pytest + testcontainers: Modern testing approach with real database containers
- API-First Design: Pure REST API without template dependencies
- ViewSet Pattern: Consistent CRUD operations across all resources
- Factory Pattern: Test data generation using factory-boy
- Container Pattern: Database testing with testcontainers
- Pre-commit Hooks: Automated code quality enforcement
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β FitHub System Architecture β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
βββββββββββββββββββ βββββββββββββββββββ βββββββββββββββββββ
β Client Apps β β API Gateway β β Data Layer β
β β β β β β
β β’ Web Frontend βββββΊβ β’ Django DRF βββββΊβ β’ PostgreSQL β
β β’ Mobile App β β β’ Authenticationβ β β’ Redis Cache β
β β’ Third-party β β β’ Rate Limiting β β β’ File Storage β
βββββββββββββββββββ βββββββββββββββββββ βββββββββββββββββββ
β
βΌ
βββββββββββββββββββ
β Infrastructureβ
β β
β β’ Docker β
β β’ CI/CD β
β β’ Monitoring β
βββββββββββββββββββ
For detailed deployment architecture including production, staging, and development environments, see the comprehensive C4 deployment diagram:
The C4 deployment diagram provides:
- Production Environment: Load balancer, application cluster, database cluster, monitoring
- Local Development: Docker containers for web app and PostgreSQL
- CI/CD Pipeline: GitHub Actions, Docker Hub registry
- Technology Stack: Detailed technology choices and configurations
- Security Architecture: Network, application, and data security layers
The CI pipeline documentation provides:
- 4-Stage Pipeline: Detailed flow from code commit to deployment
- Quality Gates: Code quality, security, testing, and build requirements
- Job Dependencies: Parallel and sequential job execution patterns
- Technology Stack: CI/CD tools and configurations
- Monitoring: Pipeline metrics and observability
fithub/ # Main Django project
βββ fithub/ # Project configuration
β βββ settings.py # Production settings
β βββ test_settings.py # PostgreSQL test settings
β βββ test_settings_sqlite.py # SQLite test settings
β βββ urls.py # Main URL routing
β βββ wsgi.py # WSGI configuration
β βββ asgi.py # ASGI configuration
βββ nutrition/ # Nutrition tracking app
βββ goals/ # Goals management app
βββ home/ # Home page app
βββ fitbot/ # Placeholder app
Each Django app follows a consistent structure:
app_name/
βββ models.py # Database models
βββ serializers.py # API serializers
βββ api.py # API viewsets and views
βββ api_urls.py # API URL routing
βββ factories.py # Test data factories
βββ test_api.py # API tests
βββ admin.py # Django admin configuration
βββ apps.py # App configuration
βββ migrations/ # Database migrations
βββ tests.py # Basic tests
dependencies = [
"django>=5.2.7", # Web framework
"djangorestframework>=3.16.1", # API framework
"djangorestframework-simplejwt>=5.5.1", # JWT authentication
"django-filter>=24.2", # API filtering
"django-cors-headers>=4.3.1", # CORS handling
"drf-spectacular>=0.27.0", # OpenAPI documentation
"pillow>=11.3.0", # Image processing
"psycopg2-binary>=2.9.10", # PostgreSQL adapter
"python-dotenv>=1.1.1", # Environment variables
]test = [
"pytest>=8.0.0", # Testing framework
"pytest-django>=4.8.0", # Django testing integration
"pytest-cov>=4.0.0", # Coverage reporting
"factory-boy>=3.3.0", # Test data factories
"faker>=22.0.0", # Fake data generation
"testcontainers>=3.7.0", # Database containers
"docker>=6.1.0", # Docker integration
"black>=23.0.0", # Code formatting
"isort>=5.12.0", # Import sorting
"flake8>=6.0.0", # Linting
"bandit>=1.7.0", # Security analysis
"safety>=2.3.0", # Dependency vulnerability scanning
]
dev = [
"pre-commit>=4.3.0", # Git hooks
]- Why uv: Significantly faster than pip, better dependency resolution
- Lock File:
uv.lockensures reproducible builds - Virtual Environment: Automatic
.venvmanagement - Commands:
uv sync,uv add,uv run
- Production: Core runtime dependencies
- Test: Testing and quality assurance tools
- Dev: Development workflow tools
-
JWT (Primary): Stateless, scalable for API clients
- Access tokens: 60 minutes
- Refresh tokens: 7 days
- Token rotation enabled
-
Session Authentication: For web browser clients
- CSRF protection enabled
- Session-based state management
-
Token Authentication: DRF tokens for simple API access
- Returns user information with token
- Suitable for server-to-server communication
erDiagram
USER ||--o{ DIET : creates
USER ||--o{ INGREDIENT : "creates personal"
USER ||--o{ MEAL_RECORD : logs
USER ||--o{ MEAL_PREFERENCE : has
USER ||--o{ GOAL : sets
USER ||--o{ BODY_MEASUREMENT : records
DIET ||--o{ MEAL : contains
MEAL ||--o{ MEAL_INGREDIENT : contains
MEAL ||--o{ MEAL_RECORD : "can be logged as"
CATEGORY ||--o{ CATEGORY : "has parent"
CATEGORY ||--o{ INGREDIENT : contains
INGREDIENT ||--o{ MEAL_INGREDIENT : "used in"
INGREDIENT ||--o{ MEAL_PREFERENCE : "has preference"
USER {
int id PK
string username
string email
string first_name
string last_name
boolean is_active
datetime date_joined
}
DIET {
int id PK
string name
int user_id FK
float day_proteins_g
float day_fats_g
float day_carbohydrates_g
float day_calories_kcal
boolean is_active
date start_date
date end_date
text notes
datetime created_at
datetime updated_at
}
MEAL {
int id PK
string name
text description
int diet_id FK
boolean is_scheduled
date start_date
date end_date
time start_time
int duration_minutes
string recurrence_type
date recurrence_until
string google_calendar_event_id
datetime last_synced_to_calendar
string meal_type
datetime created_at
datetime updated_at
}
CATEGORY {
int id PK
string name
int parent_id FK
datetime created_at
datetime updated_at
}
INGREDIENT {
int id PK
string name
int category_id FK
float proteins
float fats
float carbs
float calories
float fibers
float sugars
text description
boolean is_personal
int created_by_id FK
datetime created_at
datetime updated_at
}
MEAL_INGREDIENT {
int id PK
int meal_id FK
int ingredient_id FK
string barcode
float quantity
string unit
datetime created_at
datetime updated_at
}
MEAL_RECORD {
int id PK
int meal_id FK
int user_id FK
string meal_name
float quantity_grams
float calories
float proteins
float carbs
float fats
datetime timestamp
string photo
text feedback
datetime created_at
datetime updated_at
}
MEAL_PREFERENCE {
int id PK
int user_id FK
int ingredient_id FK
string barcode
text description
string preference_type
datetime created_at
datetime updated_at
}
GOAL {
uuid id PK
int user_id FK
string goal_type
date target_date
text notes
boolean is_active
datetime created_at
datetime updated_at
}
BODY_MEASUREMENT {
int id PK
int user_id FK
string metric
string measurement_type
float value
datetime timestamp
datetime created_at
datetime updated_at
}
-
User Management
User(Django built-in)- Authentication via JWT, sessions, and tokens
-
Nutrition Domain
Category βββ βββ Ingredient βββ Diet βββββββ€ βββ MealIngredient βββ Meal βββββββββ β βββ MealRecord -
Goals Domain
Goal βββ βββ BodyMeasurement
- User Ownership: All user-specific models have a
userforeign key - Nutrition Hierarchy: Categories β Ingredients β Meals β MealRecords
- Goal Tracking: Goals β BodyMeasurements for progress tracking
- Flexible Meal Recording: MealRecord can reference planned meals or be standalone
- Preference System: MealPreference allows users to express ingredient preferences
# Category: Food categories (e.g., "Vegetables", "Proteins")
class Category(models.Model):
name = models.CharField(max_length=100)
description = models.TextField(blank=True)
# Ingredient: Individual food items with nutritional data
class Ingredient(models.Model):
name = models.CharField(max_length=200)
category = models.ForeignKey(Category, on_delete=models.CASCADE)
calories_per_100g = models.DecimalField(max_digits=8, decimal_places=2)
# ... other nutritional fields
# Diet: Collection of meals for a specific goal
class Diet(models.Model):
name = models.CharField(max_length=200)
user = models.ForeignKey(User, on_delete=models.CASCADE)
start_date = models.DateField()
end_date = models.DateField(null=True, blank=True)
is_active = models.BooleanField(default=True)
# Meal: Collection of ingredients
class Meal(models.Model):
name = models.CharField(max_length=200)
diet = models.ForeignKey(Diet, on_delete=models.CASCADE, null=True)
user = models.ForeignKey(User, on_delete=models.CASCADE)
meal_type = models.CharField(max_length=50, choices=MEAL_TYPE_CHOICES)
# MealIngredient: Junction table for meal-ingredient relationships
class MealIngredient(models.Model):
meal = models.ForeignKey(Meal, on_delete=models.CASCADE)
ingredient = models.ForeignKey(Ingredient, on_delete=models.CASCADE)
quantity = models.DecimalField(max_digits=8, decimal_places=2)
unit = models.CharField(max_length=20)
# MealRecord: Actual consumption records
class MealRecord(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
meal = models.ForeignKey(Meal, on_delete=models.CASCADE, null=True)
timestamp = models.DateTimeField()
calories = models.DecimalField(max_digits=8, decimal_places=2)# Goal: Fitness goals (weight loss, muscle gain, etc.)
class Goal(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
title = models.CharField(max_length=200)
description = models.TextField(blank=True)
goal_type = models.CharField(max_length=50, choices=GOAL_TYPE_CHOICES)
target_value = models.DecimalField(max_digits=10, decimal_places=2)
start_date = models.DateField()
target_date = models.DateField()
is_active = models.BooleanField(default=True)
# BodyMeasurement: Physical measurements over time
class BodyMeasurement(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
metric = models.CharField(max_length=50, choices=METRIC_CHOICES)
value = models.DecimalField(max_digits=8, decimal_places=2)
unit = models.CharField(max_length=20)
timestamp = models.DateTimeField()- Resource-based URLs:
/api/nutrition/diets/,/api/goals/body-measurements/ - HTTP Methods: GET, POST, PUT, PATCH, DELETE
- Status Codes: Proper HTTP status codes for all responses
- Content Negotiation: JSON responses with proper headers
class DietViewSet(viewsets.ModelViewSet):
"""
ViewSet for managing diets with full CRUD operations
"""
queryset = Diet.objects.all()
serializer_class = DietSerializer
permission_classes = [IsAuthenticated]
filter_backends = [DjangoFilterBackend, SearchFilter, OrderingFilter]
filterset_fields = ['is_active', 'start_date', 'end_date']
search_fields = ['name', 'description']
ordering_fields = ['created_at', 'start_date', 'name']
ordering = ['-created_at']@action(detail=True, methods=['post'])
def activate(self, request, pk=None):
"""Activate a diet"""
diet = self.get_object()
diet.is_active = True
diet.save()
return Response({'status': 'diet activated'})- Session Authentication: For web clients
- Token Authentication: For API clients
- CSRF Protection: Enabled for session authentication
- IsAuthenticated: All API endpoints require authentication
- User Ownership: Users can only access their own data
- Admin Access: Superusers have full access via Django admin
- drf-spectacular: Auto-generates OpenAPI 3.0 schema
- Swagger UI: Interactive API documentation at
/api/docs/ - ReDoc: Alternative documentation at
/api/redoc/ - Schema Endpoint: Raw OpenAPI schema at
/api/schema/
- Unit Tests: Individual component testing
- Integration Tests: API endpoint testing
- Container Tests: Database integration with PostgreSQL containers
class NutritionAPITestCase(APITestCase):
def setUp(self):
"""Set up test data"""
self.client = APIClient()
self.user = UserFactory()
self.client.force_authenticate(user=self.user)
def test_diet_create(self):
"""Test diet creation"""
data = {
'name': 'Test Diet',
'description': 'Test description',
'start_date': '2025-01-01'
}
response = self.client.post('/api/nutrition/diets/', data)
self.assertEqual(response.status_code, status.HTTP_201_CREATED)- factory-boy: Generates realistic test data
- faker: Creates fake but realistic data
- testcontainers: Provides isolated PostgreSQL instances
- SQLite Tests (
test_settings_sqlite.py): Fast, in-memory database - PostgreSQL Tests (
test_settings.py): Real database with containers - Production Tests (
settings.py): Full production environment
FROM python:3.13-slim
# Install system dependencies
RUN apt-get update && apt-get install -y \
postgresql-client \
&& rm -rf /var/lib/apt/lists/*
# Set working directory
WORKDIR /app
# Install Python dependencies
COPY pyproject.toml uv.lock ./
RUN pip install uv && uv sync
# Copy application code
COPY . .
# Set entrypoint
ENTRYPOINT ["/app/entrypoint.sh"]- linux/amd64: Standard x86_64 architecture
- linux/arm64: ARM64 architecture (Apple Silicon, ARM servers)
-
Code Quality (Parallel)
- Linting (flake8)
- Security scanning (bandit, safety)
- Code formatting (black, isort)
-
Testing
- Unit tests with PostgreSQL containers
- Coverage reporting
- Test result artifacts
-
Docker Build
- Multi-platform builds
- DockerHub push
- Image testing
-
Deployment
- Production deployment (main branch only)
- Environment-specific configurations
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run linting
run: make lint
test:
runs-on: ubuntu-latest
needs: [lint, security]
services:
postgres:
image: postgres:16
steps:
- name: Run tests
run: make test-ci- CSRF Protection: Enabled for session authentication
- Token Authentication: Secure API token system
- Password Hashing: Django's built-in PBKDF2 with SHA256
- User Isolation: Users can only access their own data
- Input Validation: Comprehensive serializer validation
- SQL Injection Protection: Django ORM prevents SQL injection
- bandit: Static security analysis
- safety: Dependency vulnerability scanning
- Automated Scanning: Integrated into CI/CD pipeline
- Select Related: Minimize database queries
- Pagination: Limit result sets
- Indexing: Proper database indexes on foreign keys
- Database Query Caching: Django's built-in caching
- API Response Caching: Future enhancement with Redis
- Stateless Design: API is stateless for horizontal scaling
- Database Connection Pooling: PostgreSQL connection management
- Container Orchestration: Ready for Kubernetes deployment
- Formatting: black and isort for consistent code style
- Linting: flake8 for code quality
- Type Checking: Future enhancement with mypy
- Security: bandit and safety for vulnerability scanning
# Code formatting
make format
# Linting
make lint
# Security checks
make security
# Testing
make test-fast # SQLite tests
make test # PostgreSQL tests
make test-ci # CI-style tests with coverage- Feature Branches: All development on feature branches
- Pull Requests: Code review via pull requests
- CI Checks: All checks must pass before merge
- Main Branch: Production-ready code only
- Microservices: Split into domain-specific services
- Message Queues: Celery for background tasks
- Caching Layer: Redis for session and data caching
- CDN: Static file delivery optimization
- Application Monitoring: APM tools integration
- Logging: Structured logging with ELK stack
- Metrics: Prometheus and Grafana integration
- Health Checks: Comprehensive health monitoring
- GraphQL: Alternative to REST API
- WebSocket: Real-time updates
- Rate Limiting: API usage controls
- API Versioning: Backward compatibility management