Skip to content

raffael180/exam-proctor-scheduler

Repository files navigation

Português | English

Sistema de Gestão de Escala de Fiscais 🇧🇷

PHP MySQL Bootstrap

Um sistema web simples e funcional construído em PHP e MySQL para automatizar a complexa tarefa de alocar fiscais para provas em uma escola técnica. O projeto foi desenhado para seguir regras de negócio específicas, priorizando a justiça na distribuição de tarefas e a robustez para garantir que nenhuma turma com prova fique sem supervisão.

Sobre o Projeto

A gestão manual de escalas de fiscais é um processo sujeito a erros, demorado e muitas vezes injusto. Este sistema veio da necessidade de criar uma ferramenta automática que considerasse:

  • A disponibilidade dos professores (não alocando quem já está aplicando prova).
  • Um critério de justiça (priorizando quem fiscalizou menos vezes).
  • A necessidade de múltiplos fiscais por sala.
  • Cenários de escassez de pessoal, distribuindo os recursos de forma inteligente e aleatória para não penalizar sempre as mesmas turmas.

Funcionalidades

  • CRUDs Completos: Gestão total de Professores, Disciplinas e agendamento de Provas.
  • Associação Flexível: Um professor pode lecionar múltiplas disciplinas, e uma disciplina pode ter múltiplos professores (relação Muitos-para-Muitos).
  • Geração Automática de Escala: Com um clique, o sistema gera a escala completa para um determinado dia.
  • Lógica de Justiça: O algoritmo prioriza professores que fiscalizaram menos vezes para as novas escalas.
  • Alocação Robusta (2 Passagens): O sistema primeiro garante 1 fiscal para TODAS as turmas com prova e, depois, distribui os fiscais restantes como segundo supervisor.
  • Distribuição Aleatória: Em caso de falta de fiscais para completar 2 por turma, as turmas que ficarão com apenas 1 fiscal são escolhidas de forma aleatória.
  • Visualização de Histórico: Permite consultar e excluir escalas já geradas por data.

O Algoritmo Principal

O cérebro da aplicação é um Algoritmo de Alocação com Heurística Gulosa Randomizada em Duas Passagens.

  1. Guloso: A cada passo, ele faz a escolha mais "óbvia" e justa: selecionar o professor disponível que menos fiscalizou até hoje (ORDER BY vezes_fiscalizou ASC).
  2. Randomizado: Utiliza aleatoriedade para desempate (RAND()) e para distribuir o segundo fiscal (shuffle()), garantindo que a escala não seja previsível ou injusta.
  3. Duas Passagens: Garante a cobertura mínima (1 fiscal) antes de alocar recursos extras (o 2º fiscal), tornando o sistema resiliente à falta de pessoal.

Tecnologias Utilizadas

  • Backend: PHP 7.4+ (com PDO para acesso seguro ao banco de dados)
  • Banco de Dados: MySQL 5.7+
  • Frontend: Bootstrap 5 (via CDN, para uma interface limpa e responsiva)

Como Configurar e Rodar o Projeto

  1. Clone o Repositório

    git clone [URL_DO_SEU_REPOSITORIO]
    cd [NOME_DO_DIRETORIO]
  2. Crie o Banco de Dados

    • Abra seu gerenciador de banco de dados (ex: phpMyAdmin).
    • Crie um novo banco de dados chamado escola_tecnica.
    • Abra a aba "SQL" e cole o conteúdo do script SQL abaixo.
    Clique para ver o Script SQL Completo (CREATE TABLES + INSERTs de teste)
    -- Cria o banco de dados se ele não existir e o seleciona para uso.
    CREATE DATABASE IF NOT EXISTS `escola_tecnica`;
    USE `escola_tecnica`;
    
    -- Limpa as tabelas existentes na ordem correta para evitar erros de chave estrangeira.
    DROP TABLE IF EXISTS `escola_provas`;
    DROP TABLE IF EXISTS `provas`;
    DROP TABLE IF EXISTS `professor_disciplina`;
    DROP TABLE IF EXISTS `disciplinas`;
    DROP TABLE IF EXISTS `professores`;
    
    -- Estrutura da tabela `professores`
    CREATE TABLE `professores` (
      `id` INT AUTO_INCREMENT PRIMARY KEY,
      `nome` VARCHAR(255) NOT NULL,
      `vezes_fiscalizou` INT DEFAULT 0
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
    
    -- Estrutura da tabela `disciplinas`
    CREATE TABLE `disciplinas` (
      `id` INT AUTO_INCREMENT PRIMARY KEY,
      `nome` VARCHAR(255) NOT NULL
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
    
    -- Estrutura da tabela `professor_disciplina`
    CREATE TABLE `professor_disciplina` (
      `id_professor` INT NOT NULL,
      `id_disciplina` INT NOT NULL,
      PRIMARY KEY (`id_professor`, `id_disciplina`),
      FOREIGN KEY (`id_professor`) REFERENCES `professores`(`id`) ON DELETE CASCADE,
      FOREIGN KEY (`id_disciplina`) REFERENCES `disciplinas`(`id`) ON DELETE CASCADE
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
    
    -- Estrutura da tabela `provas`
    CREATE TABLE `provas` (
      `id` INT AUTO_INCREMENT PRIMARY KEY,
      `id_disciplina` INT NOT NULL,
      `id_professor` INT NOT NULL,
      `id_turma` VARCHAR(10) NOT NULL,
      `data_prova` DATE NOT NULL,
      FOREIGN KEY (`id_disciplina`) REFERENCES `disciplinas`(`id`) ON DELETE CASCADE,
      FOREIGN KEY (`id_professor`) REFERENCES `professores`(`id`) ON DELETE CASCADE
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
    
    -- Estrutura da tabela `escala_provas`
    CREATE TABLE `escola_provas` (
      `id` INT AUTO_INCREMENT PRIMARY KEY,
      `id_turma` VARCHAR(10) NOT NULL,
      `data_prova` DATE NOT NULL,
      `id_professor_fiscal` INT NOT NULL,
      FOREIGN KEY (`id_professor_fiscal`) REFERENCES `professores`(`id`) ON DELETE CASCADE,
      INDEX `idx_data_prova` (`data_prova`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
    
    -- Inserindo dados de teste...
    INSERT INTO `professores` (`id`, `nome`, `vezes_fiscalizou`) VALUES
    (1, 'Lucas Souza', 5), (2, 'Julia Ferreira', 2), (3, 'Pedro Oliveira', 8), (4, 'Sofia Santos', 1), (5, 'Gabriel Costa', 4), (6, 'Isabella Rodrigues', 7), (7, 'Matheus Alves', 3), (8, 'Beatriz Pereira', 0), (9, 'Bruno Lima', 5), (10, 'Maria Gomes', 2), (11, 'Felipe Martins', 6), (12, 'Laura Carvalho', 4), (13, 'João Almeida', 1), (14, 'Ana Ribeiro', 9), (15, 'Rafael Silva', 3), (16, 'Mariana Dias', 5), (17, 'Gustavo Barbosa', 2), (18, 'Letícia Nunes', 0), (19, 'André Castro', 4), (20, 'Camila Rocha', 7), (21, 'Vinicius Mendes', 3), (22, 'Manuela Barros', 1), (23, 'Daniel Cunha', 6), (24, 'Amanda Farias', 5), (25, 'Thiago Azevedo', 2), (26, 'Gabriela Teixeira', 8), (27, 'Ricardo Vieira', 0), (28, 'Helena Pinto', 4), (29, 'Eduardo Araujo', 7), (30, 'Larissa Correia', 3), (31, 'Leonardo Moreira', 5), (32, 'Valentina Cardoso', 1), (33, 'Sérgio Lopes', 6), (34, 'Luana Monteiro', 2), (35, 'Fernando Gonçalves', 4), (36, 'Heloísa Magalhães', 0);
    INSERT INTO `disciplinas` (`id`, `nome`) VALUES
    (1, 'Matemática Aplicada'), (2, 'Desenvolvimento Web I'), (3, 'Redes de Computadores'), (4, 'Física para Mecatrônica'), (5, 'Química Industrial'), (6, 'Banco de Dados'), (7, 'Sistemas Operacionais'), (8, 'Eletrônica Digital'), (9, 'Língua Portuguesa Instrumental'), (10, 'Automação Industrial'), (11, 'Engenharia de Software'), (12, 'Segurança da Informação'), (13, 'Cálculo I'), (14, 'Desenvolvimento Web II'), (15, 'Protocolos de Rede'), (16, 'Termodinâmica'), (17, 'Química Orgânica'), (18, 'Modelagem de Dados'), (19, 'Arquitetura de Computadores'), (20, 'Circuitos Elétricos'), (21, 'Literatura Técnica'), (22, 'CLP e Supervisórios'), (23, 'Testes de Software'), (24, 'Criptografia'), (25, 'Geometria Analítica'), (26, 'Interface Humano-Computador'), (27, 'Administração de Redes'), (28, 'Resistência dos Materiais'), (29, 'Físico-Química'), (30, 'Big Data'), (31, 'Sistemas Embarcados'), (32, 'Microcontroladores'), (33, 'Redação Oficial'), (34, 'Robótica'), (35, 'Qualidade de Software'), (36, 'Análise Forense');
    INSERT INTO `professor_disciplina` (`id_professor`, `id_disciplina`) VALUES
    (1, 1), (1, 13), (2, 2), (2, 14), (3, 3), (3, 15), (4, 4), (5, 5), (6, 6), (6, 18), (7, 7), (8, 8), (9, 9), (10, 10), (11, 11), (12, 12), (13, 13), (14, 14), (15, 15), (16, 16), (17, 17), (18, 18), (19, 19), (20, 20), (21, 21), (22, 22), (23, 23), (24, 24), (25, 25), (26, 26), (27, 27), (28, 28), (29, 29), (30, 30), (31, 31), (32, 32), (33, 33), (34, 34), (35, 35), (36, 36), (1, 2), (18, 6);
    INSERT INTO `provas` (`id_disciplina`, `id_professor`, `id_turma`, `data_prova`) VALUES
    (1, 1, '101', '2025-09-08'), (2, 2, '102', '2025-09-08'), (3, 3, '103', '2025-09-08'), (4, 4, '104', '2025-09-08'), (5, 5, '201', '2025-09-08'), (6, 6, '202', '2025-09-08'), (7, 7, '203', '2025-09-08'), (8, 8, '204', '2025-09-08'), (9, 9, '301', '2025-09-08'), (10, 10, '302', '2025-09-08'), (11, 11, '303', '2025-09-08'), (12, 12, '304', '2025-09-08');
  3. Configure a Conexão

    • Abra o arquivo db.php.
    • Altere as variáveis $host, $dbname, $user e $pass com as credenciais do seu ambiente de banco de dados local.
  4. Execute a Aplicação

    • Coloque a pasta do projeto no diretório do seu servidor web (ex: htdocs para XAMPP, www para WAMP).
    • Abra seu navegador e acesse http://localhost/[NOME_DA_PASTA_DO_PROJETO].

Estrutura dos Arquivos

  • index.php: A página inicial com o menu de navegação.
  • db.php: Arquivo de configuração da conexão com o banco de dados.
  • professores.php: CRUD para gerenciar professores e suas associações com disciplinas.
  • disciplinas.php: CRUD para gerenciar as disciplinas.
  • provas.php: CRUD para agendar as provas.
  • get_professores_por_disciplina.php: Script auxiliar (AJAX) para popular o dropdown de professores no agendamento de provas.
  • escala.php: O "cérebro" da aplicação, onde a escala de fiscais é gerada.
  • ver_escalas.php: Página para visualizar e excluir as escalas já salvas.


Exam Proctor Scheduling System 🇬🇧/🇺🇸

PHP MySQL Bootstrap

A simple and functional web system built with PHP and MySQL to automate the complex task of assigning proctors for exams in a technical school. The project was designed to follow specific business rules, prioritizing fairness in task distribution and robustness to ensure no classroom with an exam is left unsupervised.

About The Project

Manually managing proctor schedules is a process prone to errors, time-consuming, and often unfair. This system was born from the need to create an automated tool that considers:

  • Teacher availability (not assigning those who are already administering an exam).
  • A fairness criterion (prioritizing those who have proctored the fewest times).
  • The need for multiple proctors per classroom.
  • Scenarios of staff shortages, intelligently and randomly distributing resources to avoid penalizing the same classrooms repeatedly.

Features

  • Full CRUDs: Complete management of Teachers, Subjects, and Exam scheduling.
  • Flexible Association: A teacher can teach multiple subjects, and a subject can have multiple teachers (Many-to-Many relationship).
  • Automatic Schedule Generation: With a single click, the system generates the complete proctor schedule for a given day.
  • Fairness Logic: The algorithm prioritizes teachers who have proctored fewer times for new schedules.
  • Robust Allocation (Two-Pass): The system first guarantees 1 proctor for ALL classrooms with an exam and then distributes the remaining proctors as a second supervisor.
  • Randomized Distribution: In case of a shortage of proctors to assign 2 per room, the classrooms that will have only 1 proctor are chosen randomly.
  • History Viewing: Allows for querying and deleting previously generated schedules by date.

The Core Algorithm

The application's brain is a Two-Pass Randomized Greedy Heuristic Allocation Algorithm.

  1. Greedy: At each step, it makes the most "obvious" and fair choice: selecting the available teacher who has proctored the least (ORDER BY vezes_fiscalizou ASC).
  2. Randomized: It uses randomness for tie-breaking (RAND()) and for fairly distributing the second proctor (shuffle()), ensuring the schedule is not predictable or unfair.
  3. Two-Pass: It guarantees minimum coverage (1 proctor) before allocating extra resources (the 2nd proctor), making the system resilient to staff shortages.

Tech Stack

  • Backend: PHP 7.4+ (using PDO for secure database access)
  • Database: MySQL 5.7+
  • Frontend: Bootstrap 5 (via CDN, for a clean and responsive UI)

How to Set Up and Run the Project

  1. Clone the Repository

    git clone [YOUR_REPOSITORY_URL]
    cd [PROJECT_DIRECTORY_NAME]
  2. Create the Database

    • Open your database management tool (e.g., phpMyAdmin).
    • Create a new database named escola_tecnica.
    • Open the "SQL" tab and paste the contents of the SQL script below.
    Click to see the Full SQL Script (CREATE TABLES + test INSERTs)
    -- Creates the database if it doesn't exist and selects it for use.
    CREATE DATABASE IF NOT EXISTS `escola_tecnica`;
    USE `escola_tecnica`;
    
    -- Clears existing tables in the correct order to avoid foreign key errors.
    DROP TABLE IF EXISTS `escala_provas`;
    DROP TABLE IF EXISTS `provas`;
    DROP TABLE IF EXISTS `professor_disciplina`;
    DROP TABLE IF EXISTS `disciplinas`;
    DROP TABLE IF EXISTS `professores`;
    
    -- Table structure for `professores`
    CREATE TABLE `professores` (
      `id` INT AUTO_INCREMENT PRIMARY KEY,
      `nome` VARCHAR(255) NOT NULL,
      `vezes_fiscalizou` INT DEFAULT 0
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
    
    -- Table structure for `disciplinas`
    CREATE TABLE `disciplinas` (
      `id` INT AUTO_INCREMENT PRIMARY KEY,
      `nome` VARCHAR(255) NOT NULL
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
    
    -- Table structure for `professor_disciplina`
    CREATE TABLE `professor_disciplina` (
      `id_professor` INT NOT NULL,
      `id_disciplina` INT NOT NULL,
      PRIMARY KEY (`id_professor`, `id_disciplina`),
      FOREIGN KEY (`id_professor`) REFERENCES `professores`(`id`) ON DELETE CASCADE,
      FOREIGN KEY (`id_disciplina`) REFERENCES `disciplinas`(`id`) ON DELETE CASCADE
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
    
    -- Table structure for `provas`
    CREATE TABLE `provas` (
      `id` INT AUTO_INCREMENT PRIMARY KEY,
      `id_disciplina` INT NOT NULL,
      `id_professor` INT NOT NULL,
      `id_turma` VARCHAR(10) NOT NULL,
      `data_prova` DATE NOT NULL,
      FOREIGN KEY (`id_disciplina`) REFERENCES `disciplinas`(`id`) ON DELETE CASCADE,
      FOREIGN KEY (`id_professor`) REFERENCES `professores`(`id`) ON DELETE CASCADE
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
    
    -- Table structure for `escala_provas`
    CREATE TABLE `escala_provas` (
      `id` INT AUTO_INCREMENT PRIMARY KEY,
      `id_turma` VARCHAR(10) NOT NULL,
      `data_prova` DATE NOT NULL,
      `id_professor_fiscal` INT NOT NULL,
      FOREIGN KEY (`id_professor_fiscal`) REFERENCES `professores`(`id`) ON DELETE CASCADE,
      INDEX `idx_data_prova` (`data_prova`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
    
    -- Inserting test data...
    INSERT INTO `professores` (`id`, `nome`, `vezes_fiscalizou`) VALUES
    (1, 'Lucas Souza', 5), (2, 'Julia Ferreira', 2), (3, 'Pedro Oliveira', 8), (4, 'Sofia Santos', 1), (5, 'Gabriel Costa', 4), (6, 'Isabella Rodrigues', 7), (7, 'Matheus Alves', 3), (8, 'Beatriz Pereira', 0), (9, 'Bruno Lima', 5), (10, 'Maria Gomes', 2), (11, 'Felipe Martins', 6), (12, 'Laura Carvalho', 4), (13, 'João Almeida', 1), (14, 'Ana Ribeiro', 9), (15, 'Rafael Silva', 3), (16, 'Mariana Dias', 5), (17, 'Gustavo Barbosa', 2), (18, 'Letícia Nunes', 0), (19, 'André Castro', 4), (20, 'Camila Rocha', 7), (21, 'Vinicius Mendes', 3), (22, 'Manuela Barros', 1), (23, 'Daniel Cunha', 6), (24, 'Amanda Farias', 5), (25, 'Thiago Azevedo', 2), (26, 'Gabriela Teixeira', 8), (27, 'Ricardo Vieira', 0), (28, 'Helena Pinto', 4), (29, 'Eduardo Araujo', 7), (30, 'Larissa Correia', 3), (31, 'Leonardo Moreira', 5), (32, 'Valentina Cardoso', 1), (33, 'Sérgio Lopes', 6), (34, 'Luana Monteiro', 2), (35, 'Fernando Gonçalves', 4), (36, 'Heloísa Magalhães', 0);
    INSERT INTO `disciplinas` (`id`, `nome`) VALUES
    (1, 'Applied Mathematics'), (2, 'Web Development I'), (3, 'Computer Networks'), (4, 'Physics for Mechatronics'), (5, 'Industrial Chemistry'), (6, 'Databases'), (7, 'Operating Systems'), (8, 'Digital Electronics'), (9, 'Instrumental Portuguese'), (10, 'Industrial Automation'), (11, 'Software Engineering'), (12, 'Information Security'), (13, 'Calculus I'), (14, 'Web Development II'), (15, 'Network Protocols'), (16, 'Thermodynamics'), (17, 'Organic Chemistry'), (18, 'Data Modeling'), (19, 'Computer Architecture'), (20, 'Electric Circuits'), (21, 'Technical Literature'), (22, 'PLC and SCADA'), (23, 'Software Testing'), (24, 'Cryptography'), (25, 'Analytic Geometry'), (26, 'Human-Computer Interface'), (27, 'Network Administration'), (28, 'Strength of Materials'), (29, 'Physical Chemistry'), (30, 'Big Data'), (31, 'Embedded Systems'), (32, 'Microcontrollers'), (33, 'Official Writing'), (34, 'Robotics'), (35, 'Software Quality'), (36, 'Forensic Analysis');
    INSERT INTO `professor_disciplina` (`id_professor`, `id_disciplina`) VALUES
    (1, 1), (1, 13), (2, 2), (2, 14), (3, 3), (3, 15), (4, 4), (5, 5), (6, 6), (6, 18), (7, 7), (8, 8), (9, 9), (10, 10), (11, 11), (12, 12), (13, 13), (14, 14), (15, 15), (16, 16), (17, 17), (18, 18), (19, 19), (20, 20), (21, 21), (22, 22), (23, 23), (24, 24), (25, 25), (26, 26), (27, 27), (28, 28), (29, 29), (30, 30), (31, 31), (32, 32), (33, 33), (34, 34), (35, 35), (36, 36), (1, 2), (18, 6);
    INSERT INTO `provas` (`id_disciplina`, `id_professor`, `id_turma`, `data_prova`) VALUES
    (1, 1, '101', '2025-09-08'), (2, 2, '102', '2025-09-08'), (3, 3, '103', '2025-09-08'), (4, 4, '104', '2025-09-08'), (5, 5, '201', '2025-09-08'), (6, 6, '202', '2025-09-08'), (7, 7, '203', '2025-09-08'), (8, 8, '204', '2025-09-08'), (9, 9, '301', '2025-09-08'), (10, 10, '302', '2025-09-08'), (11, 11, '303', '2025-09-08'), (12, 12, '304', '2025-09-08');
  3. Configure the Connection

    • Open the db.php file.
    • Change the $host, $dbname, $user, and $pass variables with your local database environment credentials.
  4. Run the Application

    • Place the project folder in your web server's directory (e.g., htdocs for XAMPP, www for WAMP).
    • Open your browser and navigate to http://localhost/[PROJECT_FOLDER_NAME].

File Structure

  • index.php: The homepage with the navigation menu.
  • db.php: Database connection configuration file.
  • professores.php: CRUD for managing teachers and their subject associations.
  • disciplinas.php: CRUD for managing subjects.
  • provas.php: CRUD for scheduling exams.
  • get_professores_por_disciplina.php: Helper script (AJAX) to populate the teacher dropdown when scheduling exams.
  • escala.php: The "brain" of the application, where the proctor schedule is generated.
  • ver_escalas.php: Page to view and delete saved schedules.

About

A PHP/MySQL system to automate exam proctor scheduling. It uses a smart algorithm to ensure a fair distribution based on past workload and guarantees supervisor coverage in all classrooms.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors