Skip to content

AngularJS Application Structure

The Stratpoint Timesheet Application frontend is built using AngularJS 1.x with a modular, scalable architecture that promotes maintainability and code reusability. This section details the application structure, module organization, and architectural patterns.

Application Module Structure

Main Application Module

// Actual module definition from codebase
var StratpointTSApp = angular.module('StratpointTSApp', [
    // Core Angular modules
    'ngRoute',           // Client-side routing
    'ngResource',        // RESTful resource handling
    'ngSanitize',        // HTML sanitization
    'ngCookies',         // Cookie management
    'ngAnimate',         // Animation support

    // Third-party modules
    'ngTable',           // Data table functionality
    'ngTableExport',     // Table export capabilities
    'ngCsv',             // CSV export functionality
    'ui.bootstrap',      // Bootstrap UI components
    'ui.calendar',       // Calendar integration
    'ui.select',         // Enhanced select dropdowns
    'ui.sortable',       // Drag and drop sorting
    'nsPopover',         // Popover components
    'ngTagsInput',       // Tag input functionality
    'ngLoadingSpinner',  // Loading indicators
    'angularFileUpload', // File upload handling

    // Custom application modules
    'stratpointtsCrud',        // CRUD operations module
    'StratpointTSControllers'  // Controllers module
    // Note: Services, directives, and filters are defined within the main app module
]);

Actual Module Dependencies

graph TB
    A[StratpointTSApp] --> B[Core Angular Modules]
    A --> C[Third-party Modules]
    A --> D[Custom Modules]

    B --> E[ngRoute]
    B --> F[ngResource]
    B --> G[ngSanitize]
    B --> H[ngCookies]
    B --> I[ngAnimate]

    C --> J[ui.bootstrap]
    C --> K[ngTable]
    C --> L[ui.calendar]
    C --> M[angularFileUpload]
    C --> N[ui.select]
    C --> O[ui.sortable]
    C --> P[ngTagsInput]

    D --> Q[StratpointTSControllers]
    D --> R[stratpointtsCrud]

    A --> S[Services - Defined in main module]
    A --> T[Directives - Defined in main module]
    A --> U[Filters - Defined in main module]

File Organization

Actual Directory Structure

public/
├── app/
│   ├── js/
│   │   ├── lib/                    # Third-party libraries
│   │   │   ├── angular.min.js
│   │   │   ├── angular-route.min.js
│   │   │   ├── ui-bootstrap.min.js
│   │   │   └── ...
│   │   └── mine/                   # Application code (flat structure)
│   │       ├── app.module.js       # Main application module
│   │       ├── services.js         # All services in one file
│   │       ├── navmenu.js          # Navigation menu logic
│   │       ├── controllers_auth.js # Authentication controllers
│   │       ├── controllers_timelogs.js # Timelog controllers
│   │       ├── controllers_projects.js # Project controllers
│   │       ├── controllers_dashboard.js # Dashboard controllers
│   │       ├── controllers_users.js # User controllers
│   │       ├── controllers_reports.js # Report controllers
│   │       ├── controllers_revenues.js # Revenue controllers
│   │       ├── controllers_profits.js # Profit controllers
│   │       ├── controllers_leaves.js # Leave controllers
│   │       ├── controllers_deals.js # Deal controllers
│   │       └── ... (other controller files)
│   ├── css/
│   │   ├── lib/                    # Third-party CSS
│   │   └── mine/                   # Custom styles
│   └── partials/                   # HTML templates
│       ├── login.html
│       ├── dashboard/
│       ├── tasks/
│       ├── projects/
│       ├── users/
│       └── ... (organized by feature)
└── build/
    └── js/
        └── app.js                  # Minified/concatenated application
    ├── auth/
    ├── dashboard/
    ├── timelogs/
    ├── projects/
    ├── users/
    ├── reports/
    └── common/

Application Configuration

Main Configuration

// app.config.js
StratpointTSApp.config([
    '$routeProvider', 
    '$locationProvider', 
    '$httpProvider',
    '$compileProvider',
    function($routeProvider, $locationProvider, $httpProvider, $compileProvider) {

        // Configure HTML5 mode
        $locationProvider.html5Mode({
            enabled: true,
            requireBase: false
        });

        // Configure HTTP interceptors
        $httpProvider.interceptors.push('AuthInterceptor');
        $httpProvider.interceptors.push('ErrorInterceptor');
        $httpProvider.interceptors.push('LoadingInterceptor');

        // Disable debug info in production
        if (window.APP_ENV === 'production') {
            $compileProvider.debugInfoEnabled(false);
            $compileProvider.commentDirectivesEnabled(false);
            $compileProvider.cssClassDirectivesEnabled(false);
        }

        // Configure default route
        $routeProvider.otherwise({
            redirectTo: '/dashboard'
        });
    }
]);

Route Configuration

// app.routes.js
StratpointTSApp.config(['$routeProvider', function($routeProvider) {

    $routeProvider
        // Authentication routes
        .when('/', {
            title: 'Login',
            templateUrl: 'app/partials/auth/login.html',
            controller: 'LoginController',
            controllerAs: 'vm'
        })
        .when('/login', {
            title: 'Login',
            templateUrl: 'app/partials/auth/login.html',
            controller: 'LoginController',
            controllerAs: 'vm'
        })

        // Dashboard routes
        .when('/dashboard', {
            title: 'Dashboard',
            templateUrl: 'app/partials/dashboard/index.html',
            controller: 'DashboardController',
            controllerAs: 'vm',
            permission: 'view_dashboard',
            resolve: {
                dashboardData: ['DashboardService', function(DashboardService) {
                    return DashboardService.getDashboardData();
                }]
            }
        })

        // Timesheet routes
        .when('/timelogs', {
            title: 'Timelogs',
            templateUrl: 'app/partials/timelogs/index.html',
            controller: 'TimelogController',
            controllerAs: 'vm',
            permission: 'view_timelogs'
        })
        .when('/timelogs/add', {
            title: 'Add Timelog',
            templateUrl: 'app/partials/timelogs/form.html',
            controller: 'TimelogFormController',
            controllerAs: 'vm',
            permission: 'create_timelogs'
        })
        .when('/timelogs/:id/edit', {
            title: 'Edit Timelog',
            templateUrl: 'app/partials/timelogs/form.html',
            controller: 'TimelogFormController',
            controllerAs: 'vm',
            permission: 'edit_timelogs'
        })

        // Project routes
        .when('/projects', {
            title: 'Projects',
            templateUrl: 'app/partials/projects/index.html',
            controller: 'ProjectController',
            controllerAs: 'vm',
            permission: 'view_projects'
        })
        .when('/projects/:id', {
            title: 'Project Details',
            templateUrl: 'app/partials/projects/detail.html',
            controller: 'ProjectDetailController',
            controllerAs: 'vm',
            permission: 'view_project_details'
        })

        // User management routes
        .when('/users', {
            title: 'Users',
            templateUrl: 'app/partials/users/index.html',
            controller: 'UserController',
            controllerAs: 'vm',
            permission: 'view_users'
        })
        .when('/profile', {
            title: 'Profile',
            templateUrl: 'app/partials/users/profile.html',
            controller: 'ProfileController',
            controllerAs: 'vm',
            permission: 'view_profile'
        })

        // Report routes
        .when('/reports', {
            title: 'Reports',
            templateUrl: 'app/partials/reports/index.html',
            controller: 'ReportController',
            controllerAs: 'vm',
            permission: 'view_reports'
        })
        .when('/reports/:type', {
            title: 'Report',
            templateUrl: 'app/partials/reports/detail.html',
            controller: 'ReportDetailController',
            controllerAs: 'vm',
            permission: 'view_reports'
        })

        // Error routes
        .when('/unauthorized', {
            title: 'Unauthorized',
            templateUrl: 'app/partials/errors/unauthorized.html'
        })
        .when('/not-found', {
            title: 'Not Found',
            templateUrl: 'app/partials/errors/not-found.html'
        });
}]);

Application Bootstrap

Application Initialization

// app.run.js
StratpointTSApp.run([
    '$rootScope', 
    '$location', 
    '$route',
    'AuthService', 
    'PermissionService',
    'ConfigService',
    function($rootScope, $location, $route, AuthService, PermissionService, ConfigService) {

        // Initialize application
        $rootScope.appName = 'Stratpoint Timesheet';
        $rootScope.appVersion = '2.1.0';
        $rootScope.currentUser = null;
        $rootScope.permissions = [];

        // Load application configuration
        ConfigService.loadConfig().then(function(config) {
            $rootScope.appConfig = config;
        });

        // Route change start handler
        $rootScope.$on('$routeChangeStart', function(event, next, current) {
            // Check authentication
            if (!AuthService.isAuthenticated() && next.templateUrl !== 'app/partials/auth/login.html') {
                event.preventDefault();
                $location.path('/login');
                return;
            }

            // Check permissions
            if (next.permission && !PermissionService.hasPermission(next.permission)) {
                event.preventDefault();
                $location.path('/unauthorized');
                return;
            }

            // Show loading indicator
            $rootScope.isLoading = true;
        });

        // Route change success handler
        $rootScope.$on('$routeChangeSuccess', function(event, current, previous) {
            // Update page title
            $rootScope.pageTitle = current.title || 'Timesheet';
            document.title = $rootScope.pageTitle + ' - ' + $rootScope.appName;

            // Hide loading indicator
            $rootScope.isLoading = false;

            // Track page view
            if (window.gtag) {
                gtag('config', 'GA_TRACKING_ID', {
                    page_title: $rootScope.pageTitle,
                    page_location: $location.absUrl()
                });
            }
        });

        // Route change error handler
        $rootScope.$on('$routeChangeError', function(event, current, previous, rejection) {
            console.error('Route change error:', rejection);
            $rootScope.isLoading = false;
            $location.path('/not-found');
        });

        // Global error handler
        $rootScope.$on('$error', function(event, error) {
            console.error('Application error:', error);
            // Send error to monitoring service
            if (window.Sentry) {
                Sentry.captureException(error);
            }
        });

        // Initialize user session
        if (AuthService.isAuthenticated()) {
            AuthService.getCurrentUser().then(function(user) {
                $rootScope.currentUser = user;
                $rootScope.permissions = PermissionService.getUserPermissions(user);
            });
        }
    }
]);

Module Organization Patterns

Controller Module Structure

// controllers/timesheet/timesheet.module.js
angular.module('StratpointTSControllers.Timesheet', [])
    .controller('TimelogController', TimelogController)
    .controller('TimelogFormController', TimelogFormController)
    .controller('TimelogApprovalController', TimelogApprovalController);

// Register with main controllers module
angular.module('StratpointTSControllers', [
    'StratpointTSControllers.Auth',
    'StratpointTSControllers.Dashboard',
    'StratpointTSControllers.Timesheet',
    'StratpointTSControllers.Project',
    'StratpointTSControllers.User',
    'StratpointTSControllers.Report'
]);

Service Module Structure

// services/data/data.module.js
angular.module('StratpointTSServices.Data', [])
    .factory('ApiService', ApiService)
    .factory('CacheService', CacheService)
    .factory('SyncService', SyncService);

// Register with main services module
angular.module('StratpointTSServices', [
    'StratpointTSServices.Auth',
    'StratpointTSServices.Data',
    'StratpointTSServices.Utility',
    'StratpointTSServices.Integration'
]);

Directive Module Structure

// directives/common/common.module.js
angular.module('StratpointTSDirectives.Common', [])
    .directive('tsLoading', LoadingDirective)
    .directive('tsPermission', PermissionDirective)
    .directive('tsDatePicker', DatePickerDirective);

// Register with main directives module
angular.module('StratpointTSDirectives', [
    'StratpointTSDirectives.Common',
    'StratpointTSDirectives.Forms',
    'StratpointTSDirectives.UI'
]);

Build and Deployment Structure

Gulp Build Configuration

// gulpfile.js
var gulp = require('gulp');
var concat = require('gulp-concat');
var uglify = require('gulp-uglify');
var ngAnnotate = require('gulp-ng-annotate');

// Application JavaScript files in dependency order
var appFiles = [
    'public/app/js/mine/app.module.js',
    'public/app/js/mine/app.config.js',
    'public/app/js/mine/app.routes.js',
    'public/app/js/mine/app.run.js',
    'public/app/js/mine/controllers/**/*.js',
    'public/app/js/mine/services/**/*.js',
    'public/app/js/mine/directives/**/*.js',
    'public/app/js/mine/filters/**/*.js',
    'public/app/js/mine/factories/**/*.js'
];

// Build task
gulp.task('build-js', function() {
    return gulp.src(appFiles)
        .pipe(concat('app.min.js'))
        .pipe(ngAnnotate())
        .pipe(uglify())
        .pipe(gulp.dest('public/dist/js/'));
});

Development vs Production Structure

Development Mode: - Individual file loading for debugging - Source maps enabled - Debug information available - Hot reloading support

Production Mode: - Concatenated and minified files - Template caching - Debug information disabled - Optimized for performance

This AngularJS structure provides a scalable, maintainable foundation for the Stratpoint Timesheet Application frontend, ensuring clear separation of concerns and efficient development workflows.