Files
TimeTracker/docs/implementation-notes/ARCHITECTURE_MIGRATION_GUIDE.md
T
Dries Peeters 29f7186ee8 docs: Reorganize documentation structure for better navigation
Complete reorganization of project documentation to improve discoverability,
navigation, and maintainability. All documentation has been restructured into
a clear, role-based hierarchy.

## Major Changes

### New Directory Structure
- Created `docs/api/` for API documentation
- Created `docs/admin/` with subdirectories:
  - `admin/configuration/` - Configuration guides
  - `admin/deployment/` - Deployment guides
  - `admin/security/` - Security documentation
  - `admin/monitoring/` - Monitoring and analytics
- Created `docs/development/` for developer documentation
- Created `docs/guides/` for user-facing guides
- Created `docs/reports/` for analysis reports and summaries
- Created `docs/changelog/` for detailed changelog entries (ready for future use)

### File Organization

#### Moved from Root Directory (40+ files)
- Implementation notes → `docs/implementation-notes/`
- Test reports → `docs/testing/`
- Analysis reports → `docs/reports/`
- User guides → `docs/guides/`

#### Reorganized within docs/
- API documentation → `docs/api/`
- Administrator documentation → `docs/admin/` (with subdirectories)
- Developer documentation → `docs/development/`
- Security documentation → `docs/admin/security/`
- Telemetry documentation → `docs/admin/monitoring/`

### Documentation Updates

#### docs/README.md
- Complete rewrite with improved navigation
- Added visual documentation map
- Organized by role (Users, Administrators, Developers)
- Better categorization and quick links
- Updated all internal links to new structure

#### README.md (root)
- Updated all documentation links to reflect new structure
- Fixed 8 broken links

#### app/templates/main/help.html
- Enhanced "Where can I get additional help?" section
- Added links to new documentation structure
- Added documentation index link
- Added admin documentation link for administrators
- Improved footer with organized documentation links
- Added "Complete Documentation" section with role-based links

### New Index Files
- Created README.md files for all new directories:
  - `docs/api/README.md`
  - `docs/guides/README.md`
  - `docs/reports/README.md`
  - `docs/development/README.md`
  - `docs/admin/README.md`

### Cleanup
- Removed empty `docs/security/` directory (moved to `admin/security/`)
- Removed empty `docs/telemetry/` directory (moved to `admin/monitoring/`)
- Root directory now only contains: README.md, CHANGELOG.md, LICENSE

## Results

**Before:**
- 45+ markdown files cluttering root directory
- Documentation scattered across root and docs/
- Difficult to find relevant documentation
- No clear organization structure

**After:**
- 3 files in root directory (README, CHANGELOG, LICENSE)
- Clear directory structure organized by purpose and audience
- Easy navigation with role-based organization
- All documentation properly categorized
- Improved discoverability

## Benefits

1. Better Organization - Documentation grouped by purpose and audience
2. Easier Navigation - Role-based sections (Users, Admins, Developers)
3. Improved Discoverability - Clear structure with README files in each directory
4. Cleaner Root - Only essential files at project root
5. Maintainability - Easier to add and organize new documentation

## Files Changed

- 40+ files moved from root to appropriate docs/ subdirectories
- 15+ files reorganized within docs/
- 3 major documentation files updated (docs/README.md, README.md, help.html)
- 5 new README index files created
- 2 empty directories removed

All internal links have been updated to reflect the new structure.
2025-12-14 07:56:07 +01:00

459 lines
10 KiB
Markdown

# Architecture Migration Guide
**Complete guide for migrating existing code to the new architecture**
---
## 🎯 Overview
This guide helps you migrate existing routes and code to use the new service layer, repository pattern, and other improvements.
---
## 📋 Migration Checklist
### Step 1: Identify Code to Migrate
- [ ] Routes with business logic
- [ ] Direct model queries
- [ ] Manual validation
- [ ] Inconsistent error handling
- [ ] N+1 query problems
### Step 2: Create/Use Services
- [ ] Identify business logic
- [ ] Extract to service methods
- [ ] Use existing services or create new ones
### Step 3: Use Repositories
- [ ] Replace direct queries with repository calls
- [ ] Use eager loading to prevent N+1 queries
- [ ] Leverage repository methods
### Step 4: Add Validation
- [ ] Use schemas for API endpoints
- [ ] Use validation utilities for forms
- [ ] Add proper error handling
### Step 5: Update Tests
- [ ] Mock repositories in unit tests
- [ ] Test services independently
- [ ] Add integration tests
---
## 🔄 Migration Examples
### Example 1: Timer Route
**Before:**
```python
@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:**
```python
@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'])
```
### Example 2: Project List
**Before:**
```python
@route('/projects')
def list_projects():
projects = Project.query.filter_by(status='active').all()
# N+1 query when accessing project.client
return render_template('projects/list.html', projects=projects)
```
**After:**
```python
@route('/projects')
def list_projects():
repo = ProjectRepository()
projects = repo.get_active_projects(include_relations=True)
# Client eagerly loaded - no N+1 queries
return render_template('projects/list.html', projects=projects)
```
### Example 3: API Endpoint
**Before:**
```python
@api.route('/projects', methods=['POST'])
def create_project():
data = request.get_json()
if not data.get('name'):
return jsonify({'error': 'Name required'}), 400
project = Project(name=data['name'], ...)
db.session.add(project)
db.session.commit()
return jsonify(project.to_dict()), 201
```
**After:**
```python
@api.route('/projects', methods=['POST'])
def create_project():
from app.schemas import ProjectCreateSchema
from app.utils.api_responses import created_response, validation_error_response
schema = ProjectCreateSchema()
try:
data = schema.load(request.get_json())
except ValidationError as err:
return validation_error_response(err.messages)
service = ProjectService()
result = service.create_project(
name=data['name'],
client_id=data['client_id'],
created_by=current_user.id
)
if result['success']:
return created_response(result['project'].to_dict())
return error_response(result['message'])
```
---
## 🛠️ Available Services
### TimeTrackingService
- `start_timer()` - Start a timer
- `stop_timer()` - Stop active timer
- `create_manual_entry()` - Create manual entry
- `get_user_entries()` - Get user's entries
- `delete_entry()` - Delete entry
### ProjectService
- `create_project()` - Create project
- `update_project()` - Update project
- `archive_project()` - Archive project
- `get_active_projects()` - Get active projects
### InvoiceService
- `create_invoice_from_time_entries()` - Create invoice from entries
- `mark_as_sent()` - Mark invoice as sent
- `mark_as_paid()` - Mark invoice as paid
### TaskService
- `create_task()` - Create task
- `update_task()` - Update task
- `get_project_tasks()` - Get project tasks
### ExpenseService
- `create_expense()` - Create expense
- `get_project_expenses()` - Get project expenses
- `get_total_expenses()` - Get total expenses
### ClientService
- `create_client()` - Create client
- `update_client()` - Update client
- `get_active_clients()` - Get active clients
### ReportingService
- `get_time_summary()` - Get time summary
- `get_project_summary()` - Get project summary
- `get_user_productivity()` - Get user productivity
### AnalyticsService
- `get_dashboard_stats()` - Get dashboard stats
- `get_trends()` - Get time trends
---
## 📚 Available Repositories
All repositories extend `BaseRepository` with common methods:
- `get_by_id()` - Get by ID
- `get_all()` - Get all with pagination
- `find_by()` - Find by criteria
- `create()` - Create new
- `update()` - Update existing
- `delete()` - Delete
- `count()` - Count records
- `exists()` - Check existence
### Specialized Methods
**TimeEntryRepository:**
- `get_active_timer()` - Get active timer
- `get_by_user()` - Get user entries
- `get_by_project()` - Get project entries
- `get_by_date_range()` - Get by date range
- `get_billable_entries()` - Get billable entries
- `create_timer()` - Create timer
- `create_manual_entry()` - Create manual entry
- `get_total_duration()` - Get total duration
**ProjectRepository:**
- `get_active_projects()` - Get active projects
- `get_by_client()` - Get client projects
- `get_with_stats()` - Get with statistics
- `archive()` - Archive project
- `unarchive()` - Unarchive project
**InvoiceRepository:**
- `get_by_project()` - Get project invoices
- `get_by_client()` - Get client invoices
- `get_by_status()` - Get by status
- `get_overdue()` - Get overdue invoices
- `generate_invoice_number()` - Generate number
- `mark_as_sent()` - Mark as sent
- `mark_as_paid()` - Mark as paid
**TaskRepository:**
- `get_by_project()` - Get project tasks
- `get_by_assignee()` - Get assigned tasks
- `get_by_status()` - Get by status
- `get_overdue()` - Get overdue tasks
**ExpenseRepository:**
- `get_by_project()` - Get project expenses
- `get_billable()` - Get billable expenses
- `get_total_amount()` - Get total amount
---
## 🎨 Using Schemas
### For API Validation
```python
from app.schemas import ProjectCreateSchema
from app.utils.api_responses import validation_error_response
@api.route('/projects', methods=['POST'])
def create_project():
schema = ProjectCreateSchema()
try:
data = schema.load(request.get_json())
except ValidationError as err:
return validation_error_response(err.messages)
# Use validated data...
```
### For Serialization
```python
from app.schemas import ProjectSchema
schema = ProjectSchema()
return schema.dump(project)
```
---
## 🔔 Using Event Bus
### Emit Events
```python
from app.utils.event_bus import emit_event
from app.constants import WebhookEvent
emit_event(WebhookEvent.TIME_ENTRY_CREATED.value, {
'entry_id': entry.id,
'user_id': user_id
})
```
### Subscribe to Events
```python
from app.utils.event_bus import subscribe_to_event
@subscribe_to_event('time_entry.created')
def handle_time_entry_created(event_type, data):
# Handle event
pass
```
---
## 🔄 Using Transactions
### Decorator
```python
from app.utils.transactions import transactional
@transactional
def create_something():
# Auto-commits on success, rolls back on exception
pass
```
### Context Manager
```python
from app.utils.transactions import Transaction
with Transaction():
# Database operations
# Auto-commits on success, rolls back on exception
pass
```
---
## ⚡ Performance Tips
### 1. Use Eager Loading
```python
# Bad - N+1 queries
projects = Project.query.all()
for p in projects:
print(p.client.name) # N+1 query
# Good - Eager loading
from app.utils.query_optimization import eager_load_relations
query = Project.query
query = eager_load_relations(query, Project, ['client'])
projects = query.all()
```
### 2. Use Repository Methods
```python
# Repository methods already use eager loading
repo = ProjectRepository()
projects = repo.get_active_projects(include_relations=True)
```
### 3. Use Caching
```python
from app.utils.cache import cached
@cached(ttl=3600)
def expensive_operation():
# Result cached for 1 hour
pass
```
---
## 🧪 Testing Patterns
### Unit Test Service
```python
def test_service():
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
```
### Integration Test Repository
```python
def test_repository(db_session):
repo = TimeEntryRepository()
timer = repo.create_timer(user_id=1, project_id=1)
db_session.commit()
active = repo.get_active_timer(1)
assert active.id == timer.id
```
---
## 📝 Common Patterns
### Pattern 1: Create Resource
```python
service = ResourceService()
result = service.create_resource(**data)
if result['success']:
return success_response(result['resource'])
return error_response(result['message'])
```
### Pattern 2: List Resources
```python
repo = ResourceRepository()
resources = repo.get_all(limit=50, offset=0, include_relations=True)
return paginated_response(resources, page=1, per_page=50, total=100)
```
### Pattern 3: Update Resource
```python
service = ResourceService()
result = service.update_resource(resource_id, user_id, **updates)
if result['success']:
return success_response(result['resource'])
return error_response(result['message'])
```
---
## ✅ Migration Priority
### High Priority (Do First)
1. Timer routes - Core functionality
2. Invoice routes - Business critical
3. Project routes - Frequently used
4. API endpoints - External integration
### Medium Priority
5. Task routes
6. Expense routes
7. Client routes
8. Report routes
### Low Priority
9. Admin routes
10. Settings routes
11. User routes
---
## 🎓 Best Practices
1. **Always use services for business logic**
2. **Always use repositories for data access**
3. **Always use schemas for API validation**
4. **Always use response helpers for API responses**
5. **Always use constants instead of magic strings**
6. **Always eager load relations to prevent N+1**
7. **Always emit domain events for side effects**
8. **Always handle errors consistently**
---
## 📚 Reference
- **Quick Start:** `QUICK_START_ARCHITECTURE.md`
- **Full Analysis:** `PROJECT_ANALYSIS_AND_IMPROVEMENTS.md`
- **Implementation:** `IMPLEMENTATION_SUMMARY.md`
- **Examples:** Check `*_refactored.py` files
---
**Happy migrating!** 🚀