Files
TimeTracker/docs/development/MODULE_INTEGRATION_PLAN.md
Dries Peeters 083dd9f1f2 feat: Implement comprehensive module system with visibility controls
- Add centralized module registry system (ModuleRegistry) for managing
  module metadata, dependencies, and visibility across the application
- Create module helper utilities with decorators (@module_enabled) and
  helper functions for route protection and template access
- Add database migration (092) to add missing module visibility flags
  to settings and users tables for granular control
- Extend Settings and User models with additional module visibility
  flags for CRM, Finance, Tools, and Advanced features
- Implement admin module management UI for system-wide module
  enable/disable controls
- Add module checks to routes (calendar, contacts, deals, expenses,
  invoices, leads, custom_reports) to enforce visibility rules
- Update scheduled report service and report templates to respect
  module visibility settings
- Bump version to 4.8.0 in setup.py
- Add comprehensive documentation for module integration planning
  and implementation analysis
2025-12-29 14:13:32 +01:00

17 KiB

Module Integration & Visibility Control Plan

Date: 2025-01-27
Status: Planning Phase

Executive Summary

This document outlines a comprehensive plan to improve module integration in TimeTracker and implement a centralized system for enabling/disabling modules and menu items from admin settings. The goal is to create a more maintainable, flexible architecture that allows administrators to customize the application based on their needs.


Current State Analysis

Module Inventory

TimeTracker currently has 50+ modules/features organized into the following categories:

Core Modules (Always Enabled)

  • Authentication (auth) - Login, logout, profile
  • Dashboard (main) - Main dashboard
  • Projects (projects) - Project management
  • Time Tracking (timer) - Time entry, timers
  • Tasks (tasks) - Task management
  • Clients (clients) - Client management

Optional Modules (Can Be Disabled)

  1. Calendar (calendar) - Calendar view, integrations
  2. Project Templates (project_templates) - Template system
  3. Gantt Chart (gantt) - Gantt visualization
  4. Kanban Board (kanban) - Kanban task board
  5. Weekly Goals (weekly_goals) - Goal tracking
  6. Issues (issues) - Issue/bug tracking
  7. CRM Features:
    • Quotes (quotes) - Quote management
    • Contacts (contacts) - Contact management
    • Deals (deals) - Deal pipeline
    • Leads (leads) - Lead management
  8. Finance & Expenses:
    • Reports (reports) - Standard reports
    • Report Builder (custom_reports) - Custom report builder
    • Scheduled Reports (scheduled_reports) - Automated reports
    • Invoices (invoices) - Invoice management
    • Invoice Approvals (invoice_approvals) - Approval workflow
    • Recurring Invoices (recurring_invoices) - Recurring billing
    • Payments (payments) - Payment tracking
    • Payment Gateways (payment_gateways) - Gateway integration
    • Expenses (expenses) - Expense tracking
    • Mileage (mileage) - Mileage tracking
    • Per Diem (per_diem) - Per diem expenses
    • Budget Alerts (budget_alerts) - Budget monitoring
  9. Inventory (inventory) - Inventory management
  10. Analytics (analytics) - Analytics dashboard
  11. Tools & Data:
    • Integrations (integrations) - External integrations
    • Import/Export (import_export) - Data import/export
    • Saved Filters (saved_filters) - Filter management
  12. Admin Features:
    • User Management (admin) - User administration
    • Permissions (permissions) - RBAC system
    • Settings (settings) - System settings
    • Audit Logs (audit_logs) - Activity logging
    • Webhooks (webhooks) - Webhook management
    • Custom Fields (custom_field_definitions) - Field definitions
    • Link Templates (link_templates) - Link templates
    • Time Entry Templates (time_entry_templates) - Time templates
  13. Advanced Features:
    • Workflows (workflows) - Automation workflows
    • Time Approvals (time_approvals) - Time approval workflow
    • Activity Feed (activity_feed) - Activity stream
    • Recurring Tasks (recurring_tasks) - Automated tasks
    • Team Chat (team_chat) - Team messaging
    • Client Portal (client_portal) - Client-facing portal
    • Kiosk Mode (kiosk) - Kiosk interface

Current Architecture Issues

  1. No Centralized Module Registry

    • Blueprints registered directly in app/__init__.py
    • No single source of truth for module metadata
    • Hard to track module dependencies
  2. Inconsistent Visibility Control

    • Some modules have ui_allow_* flags in Settings
    • Some modules have ui_show_* flags in User
    • Many modules have no flags at all
    • No route-level protection
  3. Complex Navigation Logic

    • Navigation menu has hardcoded endpoint checks
    • Conditional rendering scattered throughout templates
    • Difficult to add/remove menu items
  4. Missing Module Flags

    • CRM features (deals, leads, contacts) have no flags
    • Many admin features have no flags
    • Advanced features have no flags
  5. No Module Dependencies

    • No way to express that one module depends on another
    • No validation when disabling modules

Proposed Solution

Phase 1: Module Registry System

Create a centralized module registry that defines:

  • Module metadata (name, description, category)
  • Dependencies between modules
  • Default visibility settings
  • Route associations

File: app/utils/module_registry.py

from dataclasses import dataclass
from typing import List, Optional, Dict
from enum import Enum

class ModuleCategory(Enum):
    CORE = "core"
    TIME_TRACKING = "time_tracking"
    PROJECT_MANAGEMENT = "project_management"
    CRM = "crm"
    FINANCE = "finance"
    INVENTORY = "inventory"
    ANALYTICS = "analytics"
    TOOLS = "tools"
    ADMIN = "admin"
    ADVANCED = "advanced"

@dataclass
class ModuleDefinition:
    id: str
    name: str
    description: str
    category: ModuleCategory
    blueprint_name: str
    default_enabled: bool = True
    requires_admin: bool = False
    dependencies: List[str] = None  # Module IDs this depends on
    settings_flag: Optional[str] = None  # Settings.ui_allow_* field name
    user_flag: Optional[str] = None  # User.ui_show_* field name
    routes: List[str] = None  # Route endpoints
    
    def __post_init__(self):
        if self.dependencies is None:
            self.dependencies = []
        if self.routes is None:
            self.routes = []

class ModuleRegistry:
    _modules: Dict[str, ModuleDefinition] = {}
    
    @classmethod
    def register(cls, module: ModuleDefinition):
        cls._modules[module.id] = module
    
    @classmethod
    def get(cls, module_id: str) -> Optional[ModuleDefinition]:
        return cls._modules.get(module_id)
    
    @classmethod
    def get_all(cls) -> Dict[str, ModuleDefinition]:
        return cls._modules.copy()
    
    @classmethod
    def get_by_category(cls, category: ModuleCategory) -> List[ModuleDefinition]:
        return [m for m in cls._modules.values() if m.category == category]
    
    @classmethod
    def is_enabled(cls, module_id: str, settings, user) -> bool:
        """Check if a module is enabled for a user"""
        module = cls.get(module_id)
        if not module:
            return False
        
        # Check system-wide setting
        if module.settings_flag:
            if not getattr(settings, module.settings_flag, True):
                return False
        
        # Check user-specific setting
        if module.user_flag:
            if not getattr(user, module.user_flag, True):
                return False
        
        # Check dependencies
        for dep_id in module.dependencies:
            if not cls.is_enabled(dep_id, settings, user):
                return False
        
        return True

Phase 2: Add Missing UI Flags

Add missing ui_allow_* flags to Settings model and ui_show_* flags to User model for all modules.

Settings Model Additions:

# CRM section (missing)
ui_allow_contacts = db.Column(db.Boolean, default=True, nullable=False)
ui_allow_deals = db.Column(db.Boolean, default=True, nullable=False)
ui_allow_leads = db.Column(db.Boolean, default=True, nullable=False)

# Admin section (missing)
ui_allow_workflows = db.Column(db.Boolean, default=True, nullable=False)
ui_allow_time_approvals = db.Column(db.Boolean, default=True, nullable=False)
ui_allow_activity_feed = db.Column(db.Boolean, default=True, nullable=False)
ui_allow_recurring_tasks = db.Column(db.Boolean, default=True, nullable=False)
ui_allow_team_chat = db.Column(db.Boolean, default=True, nullable=False)
ui_allow_client_portal = db.Column(db.Boolean, default=True, nullable=False)
ui_allow_kiosk = db.Column(db.Boolean, default=True, nullable=False)

User Model Additions:

# CRM section (missing)
ui_show_contacts = db.Column(db.Boolean, default=True, nullable=False)
ui_show_deals = db.Column(db.Boolean, default=True, nullable=False)
ui_show_leads = db.Column(db.Boolean, default=True, nullable=False)

# Admin section (missing)
ui_show_workflows = db.Column(db.Boolean, default=True, nullable=False)
ui_show_time_approvals = db.Column(db.Boolean, default=True, nullable=False)
ui_show_activity_feed = db.Column(db.Boolean, default=True, nullable=False)
ui_show_recurring_tasks = db.Column(db.Boolean, default=True, nullable=False)
ui_show_team_chat = db.Column(db.Boolean, default=True, nullable=False)
ui_show_client_portal = db.Column(db.Boolean, default=True, nullable=False)
ui_show_kiosk = db.Column(db.Boolean, default=True, nullable=False)

Phase 3: Module Checking Utilities

Create utilities for checking module availability in routes and templates.

File: app/utils/module_helpers.py

from functools import wraps
from flask import abort, redirect, url_for, current_app
from flask_login import current_user
from app.models import Settings
from app.utils.module_registry import ModuleRegistry

def module_enabled(module_id: str):
    """Decorator to require a module to be enabled"""
    def decorator(f):
        @wraps(f)
        def decorated_function(*args, **kwargs):
            settings = Settings.get_settings()
            if not ModuleRegistry.is_enabled(module_id, settings, current_user):
                if current_user.is_admin:
                    flash(f"Module '{module_id}' is disabled. Enable it in Settings.", "warning")
                    return redirect(url_for('admin.settings'))
                abort(403)
            return f(*args, **kwargs)
        return decorated_function
    return decorator

def is_module_enabled(module_id: str) -> bool:
    """Check if a module is enabled for current user"""
    if not current_user.is_authenticated:
        return False
    settings = Settings.get_settings()
    return ModuleRegistry.is_enabled(module_id, settings, current_user)

# Template helper
def init_module_helpers(app):
    @app.context_processor
    def inject_module_helpers():
        return {
            "is_module_enabled": is_module_enabled,
            "get_modules_by_category": lambda cat: ModuleRegistry.get_by_category(cat),
        }

Phase 4: Route Protection

Add route decorators to protect routes based on module flags.

Example:

@calendar_bp.route("/calendar")
@login_required
@module_enabled("calendar")
def view_calendar():
    # Route implementation
    pass

Phase 5: Navigation Refactoring

Refactor navigation menu to use module registry instead of hardcoded checks.

Benefits:

  • Centralized menu structure
  • Automatic menu item visibility
  • Easier to add/remove items
  • Consistent behavior

File: app/utils/navigation.py

from app.utils.module_registry import ModuleRegistry, ModuleCategory
from app.models import Settings
from flask_login import current_user

def build_navigation_menu(settings, user):
    """Build navigation menu structure from module registry"""
    menu = {
        "dashboard": {"enabled": True, "items": []},
        "calendar": {"enabled": False, "items": []},
        "time_tracking": {"enabled": True, "items": []},
        "crm": {"enabled": False, "items": []},
        "finance": {"enabled": False, "items": []},
        "inventory": {"enabled": False, "items": []},
        "analytics": {"enabled": False, "items": []},
        "tools": {"enabled": False, "items": []},
        "admin": {"enabled": False, "items": []},
    }
    
    # Populate menu from module registry
    for module in ModuleRegistry.get_all().values():
        if ModuleRegistry.is_enabled(module.id, settings, user):
            category_key = module.category.value
            if category_key in menu:
                menu[category_key]["enabled"] = True
                menu[category_key]["items"].append({
                    "id": module.id,
                    "name": module.name,
                    "url": url_for(f"{module.blueprint_name}.index") if hasattr(module, "index_route") else None,
                })
    
    return menu

Phase 6: Admin UI for Module Management

Create admin interface to manage module visibility.

Route: app/routes/admin.py

@admin_bp.route("/admin/modules", methods=["GET", "POST"])
@login_required
@admin_required
def manage_modules():
    """Manage module visibility settings"""
    settings = Settings.get_settings()
    
    if request.method == "POST":
        # Update module flags
        for module_id in ModuleRegistry.get_all().keys():
            flag_name = f"ui_allow_{module_id}"
            if hasattr(settings, flag_name):
                setattr(settings, flag_name, request.form.get(flag_name) == "on")
        
        db.session.commit()
        flash("Module settings updated successfully", "success")
        return redirect(url_for("admin.manage_modules"))
    
    # Group modules by category
    modules_by_category = {}
    for category in ModuleCategory:
        modules_by_category[category] = ModuleRegistry.get_by_category(category)
    
    return render_template("admin/modules.html", 
                         modules_by_category=modules_by_category,
                         settings=settings)

Template: app/templates/admin/modules.html

  • Checkboxes for each module
  • Category grouping
  • Dependency warnings
  • Save button

Phase 7: Database Migration

Create Alembic migration to add missing columns.

File: migrations/versions/XXXX_add_module_visibility_flags.py

def upgrade():
    # Add Settings columns
    op.add_column('settings', sa.Column('ui_allow_contacts', sa.Boolean(), nullable=False, server_default='true'))
    op.add_column('settings', sa.Column('ui_allow_deals', sa.Boolean(), nullable=False, server_default='true'))
    # ... etc
    
    # Add User columns
    op.add_column('users', sa.Column('ui_show_contacts', sa.Boolean(), nullable=False, server_default='true'))
    op.add_column('users', sa.Column('ui_show_deals', sa.Boolean(), nullable=False, server_default='true'))
    # ... etc

Implementation Phases

Phase 1: Foundation (Week 1)

  • Create module registry system
  • Define all module definitions
  • Create module checking utilities
  • Add route decorators

Phase 2: Database & Models (Week 1-2)

  • Create Alembic migration for missing flags
  • Update Settings model
  • Update User model
  • Test migration

Phase 3: Route Protection (Week 2)

  • Add @module_enabled decorator to all optional routes
  • Test route protection
  • Handle edge cases

Phase 4: Navigation Refactoring (Week 2-3)

  • Create navigation builder utility
  • Refactor base.html to use module registry
  • Test navigation visibility

Phase 5: Admin UI (Week 3)

  • Create admin module management page
  • Add dependency validation
  • Test admin interface

Phase 6: Testing & Documentation (Week 3-4)

  • Write unit tests
  • Write integration tests
  • Update documentation
  • Create migration guide

Module Dependencies

Critical Dependencies

  • InvoicesProjects (required)
  • PaymentsInvoices (required)
  • ExpensesProjects (optional, but recommended)
  • TasksProjects (optional, but recommended)
  • Time EntriesProjects (required)

Feature Dependencies

  • Invoice ApprovalsInvoices
  • Recurring InvoicesInvoices
  • Payment GatewaysPayments
  • Budget AlertsProjects
  • Kanban BoardTasks
  • Gantt ChartTasks
  • DealsClients
  • LeadsClients
  • ContactsClients

Benefits

  1. Centralized Management

    • Single source of truth for module metadata
    • Easy to add/remove modules
    • Clear dependency tracking
  2. Better User Experience

    • Admins can customize application
    • Users see only relevant features
    • Cleaner navigation
  3. Maintainability

    • Less code duplication
    • Easier to test
    • Clearer architecture
  4. Flexibility

    • Easy to add new modules
    • Easy to change module behavior
    • Support for module plugins (future)

Risks & Mitigation

Risk 1: Breaking Existing Functionality

Mitigation:

  • Comprehensive testing
  • Gradual rollout
  • Feature flags for new system

Risk 2: Performance Impact

Mitigation:

  • Cache module registry
  • Optimize database queries
  • Lazy loading where possible

Risk 3: Migration Complexity

Mitigation:

  • Thorough migration testing
  • Rollback plan
  • Data validation

Success Criteria

  1. All modules have visibility flags
  2. Admin can disable any module from settings
  3. Routes are protected by module flags
  4. Navigation automatically reflects module state
  5. Module dependencies are enforced
  6. All tests pass
  7. Documentation is updated

Future Enhancements

  1. Module Plugins

    • Support for third-party modules
    • Module marketplace
  2. Module Permissions

    • Fine-grained permissions per module
    • Role-based module access
  3. Module Analytics

    • Track module usage
    • Identify unused modules
  4. Module Templates

    • Pre-configured module sets
    • Industry-specific configurations

References

  • Current Settings Model: app/models/settings.py
  • Current User Model: app/models/user.py
  • Navigation Template: app/templates/base.html
  • Blueprint Registration: app/__init__.py

Next Steps:

  1. Review and approve this plan
  2. Create module registry implementation
  3. Begin Phase 1 implementation