Files
TimeTracker/QUICK_START_ARCHITECTURE.md
Dries Peeters 9d1ece5263 feat: Implement comprehensive architectural improvements and new features
This commit implements a complete architectural transformation of the TimeTracker
application, introducing modern design patterns and comprehensive feature set.

## Architecture Improvements

### Service Layer (18 Services)
- TimeTrackingService: Time entry management with timer functionality
- ProjectService: Project operations and lifecycle management
- InvoiceService: Invoice creation, management, and status tracking
- TaskService: Task management and workflow
- ExpenseService: Expense tracking and categorization
- ClientService: Client relationship management
- PaymentService: Payment processing and invoice reconciliation
- CommentService: Comment system for projects, tasks, and quotes
- UserService: User management and role operations
- NotificationService: Notification delivery system
- ReportingService: Report generation and analytics
- AnalyticsService: Event tracking and analytics
- ExportService: CSV export functionality
- ImportService: CSV import with validation
- EmailService: Email operations and invoice delivery
- PermissionService: Role-based permission management
- BackupService: Database backup operations
- HealthService: System health checks and monitoring

### Repository Layer (9 Repositories)
- BaseRepository: Generic CRUD operations
- TimeEntryRepository: Time entry data access
- ProjectRepository: Project data access with filtering
- InvoiceRepository: Invoice queries and status management
- TaskRepository: Task data access
- ExpenseRepository: Expense data access
- ClientRepository: Client data access
- UserRepository: User data access
- PaymentRepository: Payment data access
- CommentRepository: Comment data access

### Schema Layer (9 Schemas)
- Marshmallow schemas for validation and serialization
- Create, update, and full schemas for all entities
- Input validation and data transformation

### Utility Modules (15 Utilities)
- api_responses: Standardized API response helpers
- validation: Input validation utilities
- query_optimization: N+1 query prevention and eager loading
- error_handlers: Centralized error handling
- cache: Caching foundation (Redis-ready)
- transactions: Transaction management decorators
- event_bus: Domain event system
- performance: Performance monitoring decorators
- logger: Enhanced structured logging
- pagination: Pagination utilities
- file_upload: Secure file upload handling
- search: Full-text search utilities
- rate_limiting: Rate limiting helpers
- config_manager: Configuration management
- datetime_utils: Enhanced date/time utilities

## Database Improvements
- Performance indexes migration (15+ indexes)
- Query optimization utilities
- N+1 query prevention patterns

## Testing Infrastructure
- Comprehensive test fixtures (conftest.py)
- Service layer unit tests
- Repository layer unit tests
- Integration test examples

## CI/CD Pipeline
- GitHub Actions workflow
- Automated linting (Black, Flake8, Pylint)
- Security scanning (Bandit, Safety, Semgrep)
- Automated testing with coverage
- Docker image builds

## Documentation
- Architecture migration guide
- Quick start guide
- API enhancements documentation
- Implementation summaries
- Refactored route examples

## Key Benefits
- Separation of concerns: Business logic decoupled from routes
- Testability: Services and repositories can be tested in isolation
- Maintainability: Consistent patterns across codebase
- Performance: Database indexes and query optimization
- Security: Input validation and security scanning
- Scalability: Event-driven architecture and health checks

## Statistics
- 70+ new files created
- 8,000+ lines of code
- 18 services, 9 repositories, 9 schemas
- 15 utility modules
- 5 test files with examples

This transformation establishes a solid foundation for future development
and follows industry best practices for maintainable, scalable applications.
2025-11-23 20:00:10 +01:00

5.8 KiB

Quick Start: Using the New Architecture

This guide shows you how to use the new service layer, repository pattern, and other improvements.


🏗️ Architecture Overview

Routes → Services → Repositories → Models → Database

Layers

  1. Routes - Handle HTTP requests/responses
  2. Services - Business logic
  3. Repositories - Data access
  4. Models - Database models
  5. Schemas - Validation and serialization

📝 Quick Examples

Using Services in Routes

Before:

@route('/timer/start')
def start_timer():
    project = Project.query.get(project_id)
    if not project:
        return error
    timer = TimeEntry(...)
    db.session.add(timer)
    db.session.commit()

After:

from app.services import TimeTrackingService

@route('/timer/start')
def start_timer():
    service = TimeTrackingService()
    result = service.start_timer(user_id, project_id)
    if result['success']:
        return success_response(result['timer'])
    return error_response(result['message'])

Using Repositories

from app.repositories import TimeEntryRepository

repo = TimeEntryRepository()
entries = repo.get_by_user(user_id, include_relations=True)
active_timer = repo.get_active_timer(user_id)

Using Schemas for Validation

from app.schemas import TimeEntryCreateSchema
from app.utils.api_responses import validation_error_response

@route('/api/time-entries', methods=['POST'])
def create_entry():
    schema = TimeEntryCreateSchema()
    try:
        data = schema.load(request.get_json())
    except ValidationError as err:
        return validation_error_response(err.messages)
    
    # Use validated data...

Using API Response Helpers

from app.utils.api_responses import (
    success_response,
    error_response,
    paginated_response,
    created_response
)

# Success response
return success_response(data=project.to_dict(), message="Project created")

# Error response
return error_response("Project not found", error_code="not_found", status_code=404)

# Paginated response
return paginated_response(
    items=projects,
    page=1,
    per_page=50,
    total=100
)

# Created response
return created_response(data=project.to_dict(), location=f"/api/projects/{project.id}")

Using Constants

from app.constants import ProjectStatus, TimeEntrySource, InvoiceStatus

# Use enums instead of magic strings
project.status = ProjectStatus.ACTIVE.value
entry.source = TimeEntrySource.MANUAL.value
invoice.status = InvoiceStatus.DRAFT.value

Using Query Optimization

from app.utils.query_optimization import eager_load_relations, optimize_list_query

# Eagerly load relations to prevent N+1 queries
query = Project.query
query = eager_load_relations(query, Project, ['client', 'time_entries'])

# Or use auto-optimization
query = optimize_list_query(Project.query, Project)

Using Validation Utilities

from app.utils.validation import (
    validate_required,
    validate_date_range,
    validate_email,
    sanitize_input
)

# Validate required fields
validate_required(data, ['name', 'email'])

# Validate date range
validate_date_range(start_date, end_date)

# Validate email
email = validate_email(data['email'])

# Sanitize input
clean_input = sanitize_input(user_input, max_length=500)

🔄 Migration Guide

Step 1: Identify Business Logic

Find code in routes that:

  • Validates data
  • Performs calculations
  • Checks permissions
  • Creates/updates multiple models
  • Has complex conditional logic

Step 2: Extract to Service

Move business logic to a service method:

# app/services/my_service.py
class MyService:
    def do_something(self, param1, param2):
        # Business logic here
        return {'success': True, 'data': result}

Step 3: Use Repository for Data Access

Replace direct model queries with repository calls:

# Before
projects = Project.query.filter_by(status='active').all()

# After
repo = ProjectRepository()
projects = repo.get_active_projects()

Step 4: Update Route

Use service in route:

@route('/endpoint')
def my_endpoint():
    service = MyService()
    result = service.do_something(param1, param2)
    if result['success']:
        return success_response(result['data'])
    return error_response(result['message'])

🧪 Testing

Testing Services

from unittest.mock import Mock
from app.services import TimeTrackingService

def test_start_timer():
    service = TimeTrackingService()
    service.time_entry_repo = Mock()
    service.project_repo = Mock()
    
    result = service.start_timer(user_id=1, project_id=1)
    assert result['success'] == True

Testing Repositories

from app.repositories import TimeEntryRepository

def test_get_active_timer(db_session, user, project):
    repo = TimeEntryRepository()
    timer = repo.create_timer(user.id, project.id)
    db_session.commit()
    
    active = repo.get_active_timer(user.id)
    assert active.id == timer.id

📚 Additional Resources

  • Full Documentation: See IMPLEMENTATION_SUMMARY.md
  • API Documentation: See docs/API_ENHANCEMENTS.md
  • Example Code: See app/routes/projects_refactored_example.py
  • Test Examples: See tests/test_services/ and tests/test_repositories/

Best Practices

  1. Always use services for business logic - Don't put business logic in routes
  2. Use repositories for data access - Don't query models directly in routes
  3. Use schemas for validation - Don't validate manually
  4. Use response helpers - Don't create JSON responses manually
  5. Use constants - Don't use magic strings
  6. Eager load relations - Prevent N+1 queries
  7. Handle errors consistently - Use error response helpers

Happy coding! 🚀