Skip to content

Database Design

The Stratpoint Timesheet Application uses a comprehensive relational database design built on MySQL. The database schema is designed to support complex business requirements while maintaining data integrity, performance, and scalability.

Database Schema Overview

Core Entity Relationships

erDiagram
    %% Core User Management
    USERS {
        bigint id PK
        varchar firstname
        varchar lastname
        varchar email UK
        varchar password
        bigint role_id FK
        bigint designation_id FK
        bigint job_family_id FK
        bigint approverUser_id FK
        boolean isActive
        boolean isAnApprover
        decimal currentHourlyCost
        varchar netsuiteId
        timestamp created_at
        timestamp updated_at
    }

    ROLES {
        bigint id PK
        varchar name UK
        varchar description
        boolean isActive
        timestamp created_at
    }

    DESIGNATIONS {
        bigint id PK
        varchar name UK
        varchar description
        boolean isActive
        timestamp created_at
    }

    JOB_FAMILIES {
        bigint id PK
        varchar name UK
        varchar description
        boolean isActive
        timestamp created_at
    }

    %% Project Management
    PROJECTS {
        bigint id PK
        varchar name
        varchar description
        bigint client_id FK
        bigint project_status_id FK
        bigint project_type_id FK
        date startDate
        date endDate
        decimal budget
        varchar netsuiteId
        boolean isActive
        timestamp created_at
        timestamp updated_at
    }

    CLIENTS {
        bigint id PK
        varchar name UK
        varchar description
        varchar contactEmail
        varchar contactPhone
        boolean isActive
        timestamp created_at
    }

    PROJECT_STATUS {
        bigint id PK
        varchar name UK
        varchar description
        varchar color
        boolean isActive
    }

    PROJECT_TYPES {
        bigint id PK
        varchar name UK
        varchar description
        boolean isActive
    }

    PROJECT_USERS {
        bigint id PK
        bigint project_id FK
        bigint user_id FK
        date startDate
        date endDate
        decimal hourlyRate
        boolean isActive
        timestamp created_at
    }

    %% Time Tracking
    TIMELOGS {
        bigint id PK
        bigint user_id FK
        bigint project_user_id FK
        bigint tasktype_id FK
        date logDate
        decimal hours
        varchar description
        varchar location
        boolean isApproved
        bigint approvedBy FK
        timestamp approvedAt
        timestamp created_at
        timestamp updated_at
    }

    TASKTYPES {
        bigint id PK
        varchar name UK
        varchar description
        varchar category
        boolean isActive
        timestamp created_at
    }

    %% Leave Management
    LEAVES {
        bigint id PK
        bigint user_id FK
        bigint leave_type_id FK
        date startDate
        date endDate
        decimal days
        varchar reason
        varchar status
        bigint approvedBy FK
        timestamp approvedAt
        timestamp created_at
        timestamp updated_at
    }

    LEAVE_TYPES {
        bigint id PK
        varchar name UK
        varchar description
        decimal maxDays
        boolean requiresApproval
        boolean isActive
        timestamp created_at
    }

    %% Authorization
    PERMISSIONS {
        bigint id PK
        varchar name UK
        varchar description
        varchar module
        varchar action
        timestamp created_at
    }

    ROLE_PERMISSIONS {
        bigint id PK
        bigint role_id FK
        bigint permission_id FK
        timestamp created_at
    }

    %% Relationships
    USERS ||--o{ TIMELOGS : "creates"
    USERS ||--o{ PROJECT_USERS : "assigned_to"
    USERS ||--o{ LEAVES : "requests"
    USERS }|--|| ROLES : "has_role"
    USERS }|--|| DESIGNATIONS : "has_designation"
    USERS }|--|| JOB_FAMILIES : "belongs_to"
    USERS ||--o{ USERS : "approves"

    PROJECTS ||--o{ PROJECT_USERS : "contains"
    PROJECTS }|--|| CLIENTS : "belongs_to"
    PROJECTS }|--|| PROJECT_STATUS : "has_status"
    PROJECTS }|--|| PROJECT_TYPES : "has_type"

    PROJECT_USERS ||--o{ TIMELOGS : "tracks_time"

    TIMELOGS }|--|| TASKTYPES : "categorized_by"
    TIMELOGS }|--|| USERS : "approved_by"

    LEAVES }|--|| LEAVE_TYPES : "has_type"
    LEAVES }|--|| USERS : "approved_by"

    ROLES ||--o{ ROLE_PERMISSIONS : "has"
    PERMISSIONS ||--o{ ROLE_PERMISSIONS : "granted_to"

Core Tables

Users Table

The central table for all system users and employees:

CREATE TABLE users (
    id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
    firstname VARCHAR(255) NOT NULL,
    midname VARCHAR(255),
    lastname VARCHAR(255) NOT NULL,
    email VARCHAR(255) UNIQUE NOT NULL,
    password VARCHAR(255),
    position_id BIGINT UNSIGNED,
    designation_id BIGINT UNSIGNED,
    job_family_id BIGINT UNSIGNED,
    role_id BIGINT UNSIGNED NOT NULL,
    companyBooking_id BIGINT UNSIGNED,
    startDate DATE,
    endDate DATE,
    regularizationDate DATE,
    employmentType_id BIGINT UNSIGNED,
    businessUnit_id BIGINT UNSIGNED,
    businessLine_id BIGINT UNSIGNED,
    approverUser_id BIGINT UNSIGNED,
    isAnApprover BOOLEAN DEFAULT FALSE,
    isActive BOOLEAN DEFAULT TRUE,
    isCadet BOOLEAN DEFAULT FALSE,
    isSeniorLeader BOOLEAN DEFAULT FALSE,
    currentHourlyCost DECIMAL(10,2),
    hourlyCostEffectiveDate DATE,
    cardNumber VARCHAR(50),
    netsuiteId VARCHAR(100),
    netsuiteBranch_id BIGINT UNSIGNED,
    province_id BIGINT UNSIGNED,
    municipality_id BIGINT UNSIGNED,
    capability_id BIGINT UNSIGNED,
    techMentorUserId BIGINT UNSIGNED,
    userPriority_id BIGINT UNSIGNED,
    defaultTimelogLocation VARCHAR(255),
    permission_ids TEXT,
    plainTags TEXT,
    comments TEXT,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    deleted_at TIMESTAMP NULL,

    INDEX idx_users_email (email),
    INDEX idx_users_active (isActive),
    INDEX idx_users_role (role_id),
    INDEX idx_users_approver (approverUser_id),
    INDEX idx_users_enddate (endDate),
    INDEX idx_users_cardnumber (cardNumber)
);

Projects Table

Central table for project management:

CREATE TABLE projects (
    id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(255) NOT NULL,
    client_id BIGINT UNSIGNED NOT NULL,
    companyBooking_id BIGINT UNSIGNED,
    projectStatus_id BIGINT UNSIGNED NOT NULL,
    projectType_id BIGINT UNSIGNED NOT NULL,
    businessUnit_id BIGINT UNSIGNED,
    businessLine_id BIGINT UNSIGNED,
    ownerUser_id BIGINT UNSIGNED,
    salesUser_id BIGINT UNSIGNED,
    startDate DATE,
    endDate DATE,
    actualStartDate DATE,
    actualEndDate DATE,
    oldEndDate DATE,
    pricegroup_id BIGINT UNSIGNED,
    hexcolor_id BIGINT UNSIGNED,
    sowType_id BIGINT UNSIGNED,
    currency_id BIGINT UNSIGNED,
    netsuiteBranch_id BIGINT UNSIGNED,
    netSuiteMainId VARCHAR(100),
    netsuiteCustomer_id BIGINT UNSIGNED,
    parentProjectId BIGINT UNSIGNED,
    dealId BIGINT UNSIGNED,
    initialContractValue DECIMAL(15,2),
    discountPercent DECIMAL(5,2) DEFAULT 0,
    po_number VARCHAR(255),
    uses_foreign_currency BOOLEAN DEFAULT FALSE,
    foreign_currency VARCHAR(10),
    exchange_rate DECIMAL(10,4),
    hasSOW BOOLEAN DEFAULT FALSE,
    sowValidity DATE,
    hasSignedProposal BOOLEAN DEFAULT FALSE,
    is_coca_required BOOLEAN DEFAULT FALSE,
    isTemplateOnly BOOLEAN DEFAULT FALSE,
    isStaffAug BOOLEAN DEFAULT FALSE,
    isForTraining BOOLEAN DEFAULT FALSE,
    includeInMaDashboard BOOLEAN DEFAULT FALSE,
    treatAsMaInPmDashboard BOOLEAN DEFAULT FALSE,
    paymentMilestoneLastComputed TIMESTAMP NULL,
    notes TEXT,
    plainTags TEXT,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    deleted_at TIMESTAMP NULL,

    INDEX idx_projects_client (client_id),
    INDEX idx_projects_status (projectStatus_id),
    INDEX idx_projects_owner (ownerUser_id),
    INDEX idx_projects_dates (startDate, endDate),
    INDEX idx_projects_netsuite (netSuiteMainId)
);

Timelogs Table

Core table for time tracking entries:

CREATE TABLE timelogs (
    id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
    user_id BIGINT UNSIGNED NOT NULL,
    project_user_id BIGINT UNSIGNED,
    tasktype_id BIGINT UNSIGNED NOT NULL,
    subTaskTypeId BIGINT UNSIGNED,
    subProjectId BIGINT UNSIGNED,
    skillSetId BIGINT UNSIGNED,
    approverUser_id BIGINT UNSIGNED,
    startTime DATETIME NOT NULL,
    stopTime DATETIME NOT NULL,
    spentHours DECIMAL(8,2) NOT NULL,
    description TEXT NOT NULL,
    ticketNumber VARCHAR(255),
    location VARCHAR(255),
    status ENUM('pending', 'approved', 'rejected', 'closed') DEFAULT 'pending',
    statusNote TEXT,
    rejectReasonType VARCHAR(255),
    dateStatusChange TIMESTAMP NULL,
    statusChangedByUser_id BIGINT UNSIGNED,
    statusLog TEXT,
    changedByUserName VARCHAR(255),
    dateMadeUneditable TIMESTAMP NULL,
    toBeUsedForOffset BOOLEAN DEFAULT FALSE,
    availableHoursForOffset DECIMAL(8,2) DEFAULT 0,
    availableHoursForOffsetFromCarryOver DECIMAL(8,2) DEFAULT 0,
    dateFirstUsedAsOffset DATE,
    parentOffsetTimelog_id BIGINT UNSIGNED,
    offsetReason TEXT,
    offsetReasonType VARCHAR(255),
    offsetReasonOthers TEXT,
    ctoExpiryDate DATE,
    ctoExpiredHours DECIMAL(8,2) DEFAULT 0,
    balanceAfterLeaveAdjustment DECIMAL(8,2),
    carryOver DECIMAL(8,2) DEFAULT 0,
    convertToCash DECIMAL(8,2) DEFAULT 0,
    forfeit DECIMAL(8,2) DEFAULT 0,
    isIrSr BOOLEAN DEFAULT FALSE,
    hasNightShift BOOLEAN DEFAULT FALSE,
    nightShiftAmMinutes INT DEFAULT 0,
    nightShiftPmMinutes INT DEFAULT 0,
    plainTags TEXT,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    deleted_at TIMESTAMP NULL,

    INDEX idx_timelogs_user_date (user_id, startTime),
    INDEX idx_timelogs_project_user (project_user_id),
    INDEX idx_timelogs_status (status),
    INDEX idx_timelogs_approver (approverUser_id),
    INDEX idx_timelogs_parent_offset (parentOffsetTimelog_id),
    INDEX idx_timelogs_tasktype (tasktype_id),
    INDEX idx_timelogs_dates (startTime, stopTime)
);

Supporting Tables

Project Users Table

Links users to projects with assignment details:

CREATE TABLE project_users (
    id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
    project_id BIGINT UNSIGNED NOT NULL,
    user_id BIGINT UNSIGNED NOT NULL,
    position_id BIGINT UNSIGNED,
    projectPhase_id BIGINT UNSIGNED,
    utilizationStatus_id BIGINT UNSIGNED,
    startDate DATE,
    endDate DATE,
    percentAllocation DECIMAL(5,2) DEFAULT 100,
    budgetedHours DECIMAL(8,2),
    bufferedHours DECIMAL(8,2),
    spentHours DECIMAL(8,2) DEFAULT 0,
    initialSpentHours DECIMAL(8,2) DEFAULT 0,
    hourlyCost DECIMAL(10,2),
    hourlyRate DECIMAL(10,2),
    hourlySalary TEXT, -- Encrypted
    costMarkup DECIMAL(5,2),
    reviewStatus VARCHAR(50),
    reviewNote TEXT,
    isScrumMaster BOOLEAN DEFAULT FALSE,
    canLogMin1HourCTO BOOLEAN DEFAULT FALSE,
    commitmentType VARCHAR(50),
    plainTags TEXT,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    deleted_at TIMESTAMP NULL,

    UNIQUE KEY unique_project_user (project_id, user_id),
    INDEX idx_project_users_project (project_id),
    INDEX idx_project_users_user (user_id),
    INDEX idx_project_users_dates (startDate, endDate)
);

Leave Management Tables

Leave Availability Table:

CREATE TABLE leave_availability (
    id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
    user_id BIGINT UNSIGNED NOT NULL,
    year YEAR NOT NULL,
    taskType_id BIGINT UNSIGNED NOT NULL,
    amountInHours DECIMAL(8,2) NOT NULL,
    amountInDays DECIMAL(6,2) NOT NULL,
    awardedAmountInDays DECIMAL(6,2) DEFAULT 0,
    lastProcessedDate DATE,
    logs JSON,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,

    UNIQUE KEY unique_user_year_tasktype (user_id, year, taskType_id),
    INDEX idx_leave_availability_user_year (user_id, year),
    INDEX idx_leave_availability_tasktype (taskType_id)
);

Leave Adjustments Table:

CREATE TABLE leave_adjustments (
    id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
    user_id BIGINT UNSIGNED NOT NULL,
    year YEAR NOT NULL,
    taskType_id BIGINT UNSIGNED NOT NULL,
    userEmployment_id BIGINT UNSIGNED,
    startDate DATE NOT NULL,
    endDate DATE NOT NULL,
    amountInHours DECIMAL(8,2) NOT NULL,
    amountInDays DECIMAL(6,2) NOT NULL,
    includeWeekends BOOLEAN DEFAULT FALSE,
    logs JSON,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,

    INDEX idx_leave_adjustments_user_year (user_id, year),
    INDEX idx_leave_adjustments_dates (startDate, endDate)
);

Financial Tables

Payment Milestones Table

CREATE TABLE payment_milestones (
    id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
    project_id BIGINT UNSIGNED NOT NULL,
    name VARCHAR(255) NOT NULL,
    description TEXT,
    amount DECIMAL(15,2) NOT NULL,
    grossBilledAmountPhp DECIMAL(15,2),
    netBilledAmount DECIMAL(15,2),
    discountAmount DECIMAL(15,2) DEFAULT 0,
    discountForex DECIMAL(10,4) DEFAULT 1,
    earlyDiscountAmount DECIMAL(15,2) DEFAULT 0,
    interestAmount DECIMAL(15,2) DEFAULT 0,
    dueDate DATE,
    billedDate DATE,
    paidDate DATE,
    collectionStatus_id BIGINT UNSIGNED,
    latestCollectionNotice_id BIGINT UNSIGNED,
    paymentMilestoneStatus_id BIGINT UNSIGNED NOT NULL,
    notes TEXT,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    deleted_at TIMESTAMP NULL,

    INDEX idx_payment_milestones_project (project_id),
    INDEX idx_payment_milestones_status (paymentMilestoneStatus_id),
    INDEX idx_payment_milestones_dates (dueDate, billedDate, paidDate)
);

Revenue Tracking Tables

CREATE TABLE revenues (
    id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
    project_id BIGINT UNSIGNED NOT NULL,
    user_id BIGINT UNSIGNED NOT NULL,
    year YEAR NOT NULL,
    month TINYINT NOT NULL,
    spentHours DECIMAL(8,2) NOT NULL,
    hourlyRate DECIMAL(10,2) NOT NULL,
    amount DECIMAL(15,2) NOT NULL,
    forex DECIMAL(10,4) DEFAULT 1,
    adjustmentDifference DECIMAL(15,2) DEFAULT 0,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,

    UNIQUE KEY unique_revenue_entry (project_id, user_id, year, month),
    INDEX idx_revenues_project_period (project_id, year, month),
    INDEX idx_revenues_user_period (user_id, year, month)
);

Lookup and Reference Tables

Task Types Table

CREATE TABLE tasktypes (
    id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(255) NOT NULL,
    description TEXT,
    isOffsetable BOOLEAN DEFAULT FALSE,
    isLeaveType BOOLEAN DEFAULT FALSE,
    hexcolor_id BIGINT UNSIGNED,
    isActive BOOLEAN DEFAULT TRUE,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    deleted_at TIMESTAMP NULL,

    INDEX idx_tasktypes_active (isActive),
    INDEX idx_tasktypes_leave (isLeaveType)
);

Roles and Permissions

CREATE TABLE roles (
    id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(255) NOT NULL,
    description TEXT,
    permission_ids TEXT,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    deleted_at TIMESTAMP NULL
);

CREATE TABLE permissions (
    id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(255) NOT NULL,
    description TEXT,
    module VARCHAR(100),
    prerequisitePermission_ids TEXT,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);

Database Optimization

Indexing Strategy

Primary Indexes: - All tables have auto-incrementing primary keys - Unique constraints on business-critical combinations

Performance Indexes: - Date range queries (startTime, endTime) - Foreign key relationships - Status and active flags - User and project associations

Composite Indexes: - Multi-column indexes for common query patterns - Covering indexes for frequently accessed data

Data Integrity

Foreign Key Constraints: - Referential integrity between related tables - Cascade delete where appropriate - Restrict delete for critical relationships

Check Constraints: - Data validation at database level - Enum values for status fields - Range checks for numeric values

Performance Considerations

Partitioning: - Time-based partitioning for large tables (timelogs, revenues) - Archive old data to maintain performance

Replication: - Read replicas for reporting queries - Master-slave configuration for high availability

Caching: - Query result caching - Application-level caching for frequently accessed data

This database design provides a robust foundation for the Stratpoint Timesheet Application, supporting complex business requirements while maintaining data integrity and performance.