Skip to main content

Database Schema 🗄️

Tiger Grades utilizes a carefully designed MySQL database schema that seamlessly integrates with WordPress while providing specialized functionality for educational management. This documentation covers all custom tables, relationships, and data flow patterns.

🎯 Schema Overview

The Tiger Grades database extends WordPress with custom tables for:

  • Class Management - Course creation and organization
  • Enrollment System - Student-teacher-parent relationships
  • Feature Control - Granular permission management
  • Configuration Management - Flexible system settings
  • Audit & Security - Comprehensive activity tracking

📊 Core Tables

Classes Table (wp_tigr_classes)

The central table for all class-related information:

CREATE TABLE `wp_tigr_classes` (
`id` bigint(19) UNSIGNED NOT NULL AUTO_INCREMENT,
`teacher` bigint(19) UNSIGNED NOT NULL,
`title` varchar(45) NOT NULL,
`gradebook_id` varchar(45) DEFAULT NULL,
`status` varchar(45) NOT NULL DEFAULT 'pending',
`enrollment_code` varchar(6) DEFAULT NULL,
`created` datetime NOT NULL DEFAULT current_timestamp(),
`updated` datetime NOT NULL DEFAULT current_timestamp(),
`gradebook_url` varchar(255) DEFAULT NULL,
`num_students` bigint(19) UNSIGNED NOT NULL,
`num_categories` bigint(19) UNSIGNED NOT NULL,
`type` bigint(19) UNSIGNED NOT NULL,
`description` varchar(255) NOT NULL,
`message` varchar(512) DEFAULT NULL,
`start_date` datetime NOT NULL,
`end_date` datetime NOT NULL,
`gradebook_file_name` varchar(128) NOT NULL,

PRIMARY KEY (`id`),
UNIQUE KEY `gradebook_id_UNIQUE` (`gradebook_id`),
UNIQUE KEY `enrollment_code_UNIQUE` (`enrollment_code`),
KEY `wp_users_ID_idx` (`teacher`),
KEY `num_students_idx` (`num_students`),
KEY `num_categories_idx` (`num_categories`),
KEY `class_type_idx` (`type`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

Field Descriptions:

FieldTypeDescriptionConstraints
idBIGINTPrimary keyAUTO_INCREMENT, UNSIGNED
teacherBIGINTWordPress user ID of teacherFK to wp_users.ID
titleVARCHAR(45)Class display nameNOT NULL
gradebook_idVARCHAR(45)OneDrive file IDUNIQUE, set via Azure API
statusVARCHAR(45)pending/active/archivedDEFAULT 'pending'
enrollment_codeVARCHAR(6)Student enrollment codeUNIQUE, NULL until generated
gradebook_urlVARCHAR(255)Direct OneDrive share URLOptional
num_studentsBIGINTEstimated class sizeFK to wp_tigr_range_options
num_categoriesBIGINTGrade category countFK to wp_tigr_range_options
typeBIGINTSubject classificationFK to wp_tigr_class_types
descriptionVARCHAR(255)Class descriptionNOT NULL
messageVARCHAR(512)Welcome messageOptional
gradebook_file_nameVARCHAR(128)Excel filenameAuto-generated

Enrollments Table (wp_tigr_enrollments)

Manages student enrollments and parent-student relationships:

CREATE TABLE `wp_tigr_enrollments` (
`id` bigint(19) UNSIGNED NOT NULL AUTO_INCREMENT,
`class_id` bigint(19) UNSIGNED NOT NULL,
`user_id` bigint(19) UNSIGNED NOT NULL,
`student_name` varchar(45) NOT NULL,
`message` varchar(100) DEFAULT NULL,
`status` varchar(45) NOT NULL DEFAULT 'pending',
`student_id` int(11) DEFAULT NULL,
`created` datetime NOT NULL DEFAULT current_timestamp(),
`updated` datetime NOT NULL DEFAULT current_timestamp(),

PRIMARY KEY (`id`),
UNIQUE KEY `id_UNIQUE` (`id`),
KEY `wp_users_ID_idx` (`user_id`),
KEY `wp_tigr_classes_id_idx` (`class_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

Key Relationships:

  • class_idwp_tigr_classes.id
  • user_idwp_users.ID (parent/guardian account)
  • student_id → Position in Excel gradebook (set when approved)

Status Flow:

stateDiagram-v2
[*] --> pending: Initial submission
pending --> approved: Teacher approval
pending --> denied: Teacher denial
approved --> transferred: Move to different class
approved --> graduated: Course completion
denied --> [*]: Final state

Class Types Table (wp_tigr_class_types)

Defines available subject areas and their visual representations:

CREATE TABLE `wp_tigr_class_types` (
`id` bigint(19) UNSIGNED NOT NULL AUTO_INCREMENT,
`title` varchar(45) NOT NULL,
`image` bigint(19) UNSIGNED NOT NULL,

PRIMARY KEY (`id`),
UNIQUE KEY `title_UNIQUE` (`title`),
KEY `image_post_ID_idx` (`image`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

Default Subject Types:

INSERT INTO `wp_tigr_class_types` VALUES
(1, 'English', 1604),
(2, 'History', 1605),
(3, 'Science', 1651),
(4, 'Math', 1814),
(5, 'Foreign Language', 1820),
(6, 'Art', 1818),
(7, 'Chinese', 1819),
(8, 'PE', 1821);

🔧 Configuration & Feature Management

Feature Lookup Table (wp_tigr_feature_lookup)

Hierarchical feature management system for granular permissions:

CREATE TABLE `wp_tigr_feature_lookup` (
`id` bigint(19) UNSIGNED NOT NULL AUTO_INCREMENT,
`title` varchar(45) NOT NULL,
`description` varchar(255) NOT NULL,
`status` varchar(45) NOT NULL DEFAULT 'active',
`parent_feature` bigint(19) UNSIGNED DEFAULT NULL,

PRIMARY KEY (`id`),
KEY `parent_feature_idx` (`parent_feature`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

Feature Hierarchy Example:

user-registration (1)
├── teacher-registration-form (7)
class-registration-form (1)
├── num_students (2)
├── num_categories (3)
rest-api-routes (4)
├── /tiger-grades/v1/update-class (5)

Range Options Table (wp_tigr_range_options)

Flexible configuration for numeric ranges used throughout the system:

CREATE TABLE `wp_tigr_range_options` (
`id` bigint(19) UNSIGNED NOT NULL AUTO_INCREMENT,
`label` varchar(45) NOT NULL,
`min` int(11) NOT NULL DEFAULT 0,
`max` int(11) DEFAULT NULL,
`status` varchar(45) NOT NULL DEFAULT 'active',

PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

Example Range Configurations:

IDLabelMinMaxUsage
1'100+'100NULLLarge class sizes
4'11-30'1130Medium class sizes
5'1-10'110Small class sizes

🔗 Junction Tables

Feature Range Options Junction (wp_tigr_feature_range_options_junction)

Links features to their available range configurations:

CREATE TABLE `wp_tigr_feature_range_options_junction` (
`range_option_id` bigint(19) UNSIGNED NOT NULL,
`feature_lookup_id` bigint(19) UNSIGNED NOT NULL,

KEY `range_option_id_idx` (`range_option_id`),
KEY `feature_lookup_id_idx` (`feature_lookup_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

Secured Routes Junction (wp_tigr_secured_routes_junction)

User-specific feature access control:

CREATE TABLE `wp_tigr_secured_routes_junction` (
`user_id` bigint(20) UNSIGNED NOT NULL,
`feature_lookup_id` bigint(20) UNSIGNED NOT NULL,

KEY `user_id_idx` (`user_id`),
KEY `feature_lookup_id_idx` (`feature_lookup_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

⚡ Database Triggers

Automatic Status Management

Tiger Grades uses triggers for intelligent status updates:

-- Class status trigger
DROP TRIGGER IF EXISTS `wp_tigr_classes_BEFORE_UPDATE`;
DELIMITER $$
CREATE TRIGGER `wp_tigr_classes_BEFORE_UPDATE`
BEFORE UPDATE ON `wp_tigr_classes`
FOR EACH ROW
BEGIN
IF NEW.gradebook_id IS NOT NULL THEN
SET NEW.status = 'active';
END IF;
SET NEW.updated = CURRENT_TIMESTAMP;
END$$
DELIMITER ;

-- Enrollment approval trigger
DROP TRIGGER IF EXISTS `wp_tigr_enrollments_BEFORE_UPDATE`;
DELIMITER $$
CREATE TRIGGER `wp_tigr_enrollments_BEFORE_UPDATE`
BEFORE UPDATE ON `wp_tigr_enrollments`
FOR EACH ROW
BEGIN
IF NEW.student_id IS NOT NULL THEN
SET NEW.status = 'approved';
END IF;
SET NEW.updated = CURRENT_TIMESTAMP;
END$$
DELIMITER ;

🔄 Data Flow Patterns

Class Creation Workflow

graph TD
A[Teacher submits class form] --> B[Insert into wp_tigr_classes]
B --> C[status = 'pending']
C --> D[Azure API call]
D --> E[OneDrive gradebook created]
E --> F[Update gradebook_id]
F --> G[Trigger sets status = 'active']
G --> H[Generate enrollment_code]

Enrollment Approval Process

graph TD
A[Parent submits enrollment] --> B[Insert into wp_tigr_enrollments]
B --> C[status = 'pending']
C --> D[Teacher review]
D --> E{Approved?}
E -->|Yes| F[Update student_id]
E -->|No| G[status = 'denied']
F --> H[Trigger sets status = 'approved']
H --> I[Add to Excel gradebook]

🔍 Query Optimization

Indexing Strategy

Primary Indexes:

  • All foreign key relationships have corresponding indexes
  • Unique constraints on enrollment_code and gradebook_id
  • Composite indexes for common query patterns

Query Examples:

-- Get teacher's active classes with enrollment counts
SELECT
c.id,
c.title,
c.status,
COUNT(e.id) as enrollment_count,
ct.title as class_type
FROM wp_tigr_classes c
LEFT JOIN wp_tigr_enrollments e ON c.id = e.class_id AND e.status = 'approved'
LEFT JOIN wp_tigr_class_types ct ON c.type = ct.id
WHERE c.teacher = ? AND c.status = 'active'
GROUP BY c.id;

-- Get parent's children with their class information
SELECT
e.student_name,
c.title as class_title,
c.description,
u.display_name as teacher_name,
e.status as enrollment_status
FROM wp_tigr_enrollments e
JOIN wp_tigr_classes c ON e.class_id = c.id
JOIN wp_users u ON c.teacher = u.ID
WHERE e.user_id = ? AND e.status IN ('approved', 'pending');

🛡️ Security Considerations

Data Protection

Sensitive Information:

  • Enrollment codes are unique and expire automatically
  • Student names are stored separately from WordPress user accounts
  • Parent-student relationships are maintained through enrollments table

Access Patterns:

// Secure class access verification
function verifyClassAccess($user_id, $class_id, $role) {
switch ($role) {
case 'teacher':
return DB::table('wp_tigr_classes')
->where('id', $class_id)
->where('teacher', $user_id)
->exists();

case 'parent':
return DB::table('wp_tigr_enrollments')
->join('wp_tigr_classes', 'class_id', '=', 'wp_tigr_classes.id')
->where('wp_tigr_classes.id', $class_id)
->where('wp_tigr_enrollments.user_id', $user_id)
->where('wp_tigr_enrollments.status', 'approved')
->exists();
}
}

📊 Data Relationships

Entity Relationship Diagram

erDiagram
wp_users ||--o{ wp_tigr_classes : "teaches"
wp_users ||--o{ wp_tigr_enrollments : "parent of"
wp_tigr_classes ||--o{ wp_tigr_enrollments : "contains"
wp_tigr_class_types ||--o{ wp_tigr_classes : "categorizes"
wp_tigr_range_options ||--o{ wp_tigr_classes : "student capacity"
wp_tigr_range_options ||--o{ wp_tigr_classes : "category count"

wp_tigr_feature_lookup ||--o{ wp_tigr_feature_range_options_junction : ""
wp_tigr_range_options ||--o{ wp_tigr_feature_range_options_junction : ""

wp_users ||--o{ wp_tigr_secured_routes_junction : ""
wp_tigr_feature_lookup ||--o{ wp_tigr_secured_routes_junction : ""

🔧 Database Utilities

Migration Management

Tiger Grades includes utilities for safe database operations:

class DatabaseManager {
public function runMigration($migrationFile) {
$sql = file_get_contents($migrationFile);

// Handle @variables in SQL
$sql = $this->processVariables($sql);

// Execute with proper error handling
$this->executeSQLScript($sql);
}

private function processVariables($sql) {
// Replace @variables with actual values
$variables = [
'@wp_prefix' => $GLOBALS['wpdb']->prefix,
'@charset' => 'utf8mb4',
'@collate' => 'utf8mb4_unicode_ci'
];

return str_replace(array_keys($variables), array_values($variables), $sql);
}
}

Backup & Recovery

Automated Backup Strategy:

-- Create backup of Tiger Grades data
CREATE TABLE backup_tigr_classes_$(date) AS SELECT * FROM wp_tigr_classes;
CREATE TABLE backup_tigr_enrollments_$(date) AS SELECT * FROM wp_tigr_enrollments;

-- Restore from backup (example)
INSERT INTO wp_tigr_classes SELECT * FROM backup_tigr_classes_20240315
WHERE id NOT IN (SELECT id FROM wp_tigr_classes);

📈 Performance Monitoring

Query Performance

Slow Query Detection:

-- Monitor common query patterns
EXPLAIN SELECT
c.title,
COUNT(e.id) as student_count
FROM wp_tigr_classes c
LEFT JOIN wp_tigr_enrollments e ON c.id = e.class_id
WHERE c.teacher = 123
GROUP BY c.id;

Index Usage Analysis:

SHOW INDEX FROM wp_tigr_classes;
ANALYZE TABLE wp_tigr_enrollments;

🏆 Best Practices

For Developers

Schema Modifications:

  • Always use migrations for schema changes
  • Test changes on staging environment first
  • Maintain backward compatibility when possible
  • Document all custom field additions

Query Optimization:

  • Use appropriate indexes for foreign keys
  • Avoid N+1 query problems with eager loading
  • Cache frequently accessed configuration data
  • Monitor query performance in production

Data Integrity:

  • Rely on database constraints over application logic
  • Use transactions for multi-table operations
  • Implement proper error handling and rollback
  • Regular integrity checks and validation

Understanding the database schema is crucial for Tiger Grades development. Next, explore our API Reference to learn how to interact with this data layer.