O IFLab é uma plataforma de gerenciamento dos laboratórios do Instituto Federal de Educação, Ciência e Tecnologia de São Paulo (IFSP) - Campus Campinas. Este software oferece uma ampla gama de funcionalidades, incluindo a administração segura dos elementos e equipamentos presentes nos laboratórios de química do instituto. Além disso, dispõe de recursos para a reserva desses espaços, prevenindo conflitos de horários entre os usuários.
Bianca Ferreira de Santana Lochetti
Lucas Haiter Leoni
Mateus Rodrigues Martins
Matheus Camargo Ginebro
Note
O sistema ainda está em desenvolvimento, e qualquer erro poderá ser notificado para que possamos resolver. Para o funcionamento correto e satisfatório, é necessário que tanto a API quanto a interface estejam rodando ao mesmo tempo.
Para o funcionamento correto da API, alguns requisitos devem ser cumpridos:
1.1 A biblioteca open source OpenSSL precisa estar instalada e configurada no seu ambiente;
1.2 o arquivo .env precisa ser criado e configurado. Para mais detalhes sobre o que colocar nesse arquivo, entrar em contato com qualquer um dos desenvolvedores.
Após clonar o repositório da API, faça os seguintes passos:
1 - Rode os arquivos database.sql e inserts.sql, localizado na pasta database;
2 - É necessário que sejam rodados os seguintes comandos no terminal do vscode, estando no diretório da API:
npm i # Instala dependências da APIModo desenvolvimento:
npm run start-dev:http # Rodar em modo desenvolvimento (nodemon);Modo produção:
npm run start-prod:http # Rodar em modo produção (node);Gerar certificados:
npm run cert # Para gerar os certificados necessários;Modo desenvolvimento:
npm run start-dev:https # Rodar em modo desenvolvimento (nodemon);Modo produção:
npm run start-prod:https # Rodar em modo produção (node);Caso o terminal exiba a seguinte mensagem, a API iniciou corretamente:
[nodemon] 3.1.10 [nodemon] to restart at any time, enter `rs` [nodemon] watching path(s): *.* [nodemon] watching extensions: js,mjs,cjs,json [nodemon] starting `node /src/services/server.js src/services/server.js` HTTPS server running at https://192.168.0.51:3333Warning
O endereço IP exibido na mensagem do terminal será o mesmo endereço IP da máquina que você estiver utilzando para rodar a API. Para o melhor funcionamento do sistema, a porta :3333 precisa obrigaróriamente estar aberta.
Para o funcionamento da interface do IFLab, é necessário que:
3.1 A API esteja rodando sem erros em um IP aberto;
3.2 Seja especificado no arquivo settings.js qual é o IP atual da API;
3.3 Tanto o React Native quanto o expo estejam instalados no seu sistema;
3.4 Caso queira rodar o app no celular:
3.4.1 Se no android, deve-se instalar o aplicativo Expo Go e ler o QRCode;
3.4.2 Se no IOS, utilizar a câmera do celular para ler o QRCode.
Após clonar o repositório da interface, utilize os comandos a seguir para iniciar o app:
npm i npm run start Será gerado um QRCode que deve ser lido pelo celular. Alternativamente, também é possível pressionar a tecla w, para abrir o sistema na web.
- Registro de usuário: criação de conta com validação de e-mail institucional, senha segura e vínculo ao campus.
- Login de usuário: autenticação via e-mail institucional e senha cadastrada.
- Edição de perfil: atualização de nome, e-mail, senha, foto de perfil e tipo de usuário.
- Exibição de laboratórios: listagem de laboratórios disponíveis de acordo com o nível de permissão do usuário.
- Agendamento de sessões: reserva de horários em laboratório, incluindo elementos e equipamentos necessários.
- Inventário do laboratório: consulta e gerenciamento de elementos e equipamentos, dependendo do nível de acesso.
- Gerenciamento de acessos: controle de permissões de usuários em cada laboratório.
- Registro de campus: cadastro de novos campi e definição do primeiro usuário como administrador.
- Novas funcionalidades: possibilidade de evolução do sistema conforme surgirem novas demandas.
-
Interface e Usabilidade
- Interface responsiva e intuitiva, adaptável a diferentes telas e dispositivos.
- Ações principais (cadastro, login, agendamento) devem ser realizadas sem treinamento prévio.
- Mensagens de erro, sucesso e validação devem ser claras.
-
Desempenho
- Resposta de operações em até 2 segundos em condições normais de rede.
- Carregamento de páginas em até 3 segundos.
- Suporte a no mínimo 20 usuários simultâneos sem degradação perceptível.
-
Segurança
- Senhas criptografadas com algoritmos seguros.
- Validação de e-mails institucionais para autenticação.
- Conformidade com a LGPD.
- Proteção contra ataques como SQL Injection.
-
Disponibilidade e Confiabilidade
- Disponibilidade contínua (24/7) na rede do IFSP - Campus Campinas.
- Mensagens claras em caso de falha.
- Backups automáticos diários com retenção mínima de 30 dias.
-
Compatibilidade
- Suporte a dispositivos móveis e telas a partir de 1024x768.
- Acesso mínimo em mobile, com possibilidade futura de versão desktop (Electron).
-
Manutenibilidade e Evolução
- Código modular, documentado e seguindo boas práticas.
- Facilidade para adição de novos tipos de usuários, permissões e funcionalidades.
Method:
GET
Route:<api_ip>/campus/get
Token: não requer
Entrada:
{}Saída:
{ "status": true, "msg": "Lista de campi obtida com sucesso.", "campusList": [ { "campusId": 1, "campusName": "IFSP - Campus Campinas" } ] }Method:
POST
Route:<api_ip>/campus/register
Token: não requer
Entrada:
{ "campus_name": "IFSP - Campus Campinas", "campus_uf": "SP" }Saída:
{ "status": true, "msg": "Campus registrado com sucesso." }Method:
POST
Route:<api_ip>/users/login
Token: não requer
Entrada:
{ "user_email": "daniel.rocha@ifsp.edu.br", "user_password": "M3g4z0rd@p4ss_w0rd" }Saída:
{ "status": true, "msg": "Login realizado com sucesso.", "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjo0LCJpYXQiOjE3NjA5NjE1MDgsImV4cCI6MTc2MTA0NzkwOH0.ZS8OnDRRQytKaPXmtRYTPdQbgwJ0Iq9p5tWl43Vl3s4" }Method:
POST
Route:<api_ip>/users/logout
Token: requer
Entrada:
{}Saída:
{ "status": true, "msg": "Logout realizado com sucesso." }Method:
POST
Route:<api_ip>/users/email/getcode
Token: não requer
Important
reason_for_code = 1 Registra um novo usuário;
reason_for_code = 2 Altera email do usuário;
reason_for_code = 3 Redefine senha do usuário.
Entrada:
{ "user_email": "matheus@aluno.ifsp.edu.br", "reason_for_code": 1 }Saída:
{ "status": true, "msg": "Código de verificação enviado por email." }Method:
POST
Route:<api_ip>/users/email/validate
Token: não requer
Entrada:
{ "user_email": "matheus@aluno.ifsp.edu.br", "user_validation_code": "66887" }Saída:
{ "status": true, "msg": "Código de verificação válido.", "authToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2VtYWlsIjoibWF0aGV1c0BhbHVuby5pZnNwLmVkdS5iciIsInZlcmlmaWNhdGlvbkNvZGUiOjY2ODg3LCJpYXQiOjE3NjA5NjIwOTEsImV4cCI6MTc2MDk2NTY5MX0.dPUKidjs4xoQTZjFc2OYNyamGTaLFgGlPhZDWUNENCk" }Method:
POST
Route:<api_ip>/users/password/recovery
Token: não requer
Entrada:
{ "user_email": "matheus@aluno.ifsp.edu.br", "user_validation_code": "80198", "user_password": "C4m4rg0vs@pass" }Saída:
{ "status": true, "msg": "Senha atualizada com sucesso." }Method:
POST
Route:<api_ip>/users/register
Token: requeruser_creation_token
Entrada:
{ "user_email": "matheus@aluno.ifsp.edu.br", "user_password": "senhaT0p@123", "user_name": "Matheus Camargo Ginebro", "user_creation_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2VtYWlsIjoibWF0aGV1c0BhbHVuby5pZnNwLmVkdS5iciIsInZlcmlmaWNhdGlvbkNvZGUiOjY2ODg3LCJpYXQiOjE3NjA5NjIwOTEsImV4cCI6MTc2MDk2NTY5MX0.dPUKidjs4xoQTZjFc2OYNyamGTaLFgGlPhZDWUNENCk", "campus_id": 1 }Saída:
{ "status": true, "msg": "Usuário registrado com sucesso." }Method:
PUT
Route:<api_ip>/users/edit/name
Token: requer
Entrada:
{ "user_name": "Matheus Camargo" }Saída:
{ "status": true, "msg": "Nome do usuário atualizado com sucesso." }Method:
POST
Route:<api_ip>/users/edit/email
Token: requer
Entrada:
{ "user_email": "matheus.ginebro@aluno.ifsp.edu.br", "user_validation_code": "35250" }Saída:
{ "status": true, "msg": "Email atualizado com sucesso." }Method:
PUT
Route:<api_ip>/users/edit/password
Token: requer
Entrada:
{ "user_password": "MyN3wPass_w0rd" }Saída:
{ "status": true, "msg": "Senha do usuário atualizada com sucesso." }Method:
PUT
Route:<api_ip>/users/edit/image
Token: requer
Entrada:
{ "user_image": "URI-IMAGE" }Saída:
{ "status": true, "msg": "Imagem do usuário atualizada com sucesso." }Method:
GET
Route:<api_ip>/users/info
Token: requer
Entrada:
{}Saída:
{ "status": true, "data": { "user_id": 4, "user_name": "Matheus Camargo", "user_email": "matheus.ginebro@aluno.ifsp.edu.br", "user_type": "Funcionário", "user_access_level": "3", "user_image": null, "campus_id": 1 }, "msg": "Informações do usuário obtidas com sucesso." }Method:
POST
Route:<api_ip>/labs/register
Token: requer
Entrada:
{ "lab_name": "A102" }Saída:
{ "status": true, "msg": "Laboratório registrado com sucesso." }Method:
DELETE
Route:<api_ip>/labs/delete/<labId>
Token: requer
Entrada:
{}Saída:
{ "status": true, "msg": "Laboratório deletado com sucesso." }Method:
GET
Route:<api_ip>/labs/my
Token: requer
Entrada:
{}Saída:
{ "status": true, "msg": "Laboratórios listados com sucesso.", "labsList": [ { "labId": 1, "labName": "Lab Química A101", "userLevel": "3", "status": 0, "startsAt": "10:30:00", "endsAt": "12:30:00", "userName": "Igor Ferreira" } ] }Method:
GET
Route:<api_ip>/labs/schedule/<labId>/<date>
Token: requer
Entrada:
{}Saída:
{ "status": true, "msg": "Horário do laboratório listado com sucesso.", "scheduleList": [ { "startsAt": "11:00:00", "endsAt": "13:00:00", "date": "2025-09-11T03:00:00.000Z", "responsable": "Lucas Barros", "elementsQtd": "10.00", "equipmentsQtd": "2" }, { "startsAt": "15:00:00", "endsAt": "17:00:00", "date": "2025-09-11T03:00:00.000Z", "responsable": "Fernanda Alves", "elementsQtd": "10.00", "equipmentsQtd": "1" } ] }Method:
GET
Route:<api_ip>/labs/users/<labId>
Token: requer
Entrada:
{}Saída:
{ "status": true, "msg": "Usuários do laboratório listados com sucesso.", "usersList": [ { "userName": "Matheus Camargo", "userType": "Funcionário", "profilePic": null, "adminLevel": "3" } ] }Method:
PUT
Route:<api_ip>/labs/admin
Token: requer
Entrada:
{ "lab_id": 13, "user_id": 1, "user_admin_level": 3 }Saída:
{ "status": true, "msg": "Nível de administrador do usuário alterado com sucesso." }Method:
POST
Route:<api_ip>/labs/admin
Token: requer
Entrada:
{ "lab_id": 13, "user_id": 1, "user_admin_level": 1 }Saída:
{ "status": true, "msg": "Usuário adicionado ao laboratório com sucesso." }Method:
DELETE
Route:<api_ip>/labs/admin
Token: requer
Entrada:
{ "lab_id": 13, "user_id": 1 }Saída:
{ "status": true, "msg": "Usuário removido do laboratório com sucesso." }Method:
POST
Route:<api_ip>/elements/register
Token: requer
Entrada:
{ "element_name": "NACL - Sal de cozinha", "element_image": "no", "element_molar_mass": 1, "element_quantity": 100, "element_cas_number": "123-321", "element_ec_number": "1-222-3551", "element_admin_level": 3, "element_validity": "2026-01-01", "element_physical_state": "Sólido", "lab_id": 13 }Saída:
{ "status": true, "msg": "Elemento registrado com sucesso." }Method:
DELETE
Route:<api_ip>/elements/delete
Token: requer
Entrada:
{ "element_id": 13 }Saída:
{ "status": true, "msg": "Elemento deletado com sucesso." }Method:
GET
Route:<api_ip>/elements/lab/<labId>
Token: requer
Entrada:
{}Saída:
{ "status": true, "msg": "Elementos encontrados com sucesso", "elementsList": [ { "chemicalId": 14, "name": "NACL - Sal de cozinha", "quantity": "100.00", "molarMass": "1.00", "casNumber": "123-321", "ecNumber": "1-222-3551", "physicalState": "Sólido", "accessLevel": "3", "expirationDate": "2026-01-01T03:00:00.000Z", "image": "no", "labId": 13 } ] }Method:
GET
Route:<api_ip>/elements/session/<sessionId>
Token: requer
Entrada:
{}Saída:
{ "status": true, "msg": "Elementos encontrados com sucesso", "elementsList": [ { "element_id": 1, "element_name": "Ácido Clorídrico", "element_image": null, "element_molar_mass": "36.46", "reserved_quantity": "50.00", "element_cas_number": "7647-01-0", "element_ec_number": "231-595-7", "element_admin_level": "2", "element_validity": "2026-12-31T03:00:00.000Z", "element_physical_state": "Líquido", "lab_id": 1 } ] }Method:
GET
Route:<api_ip>/elements/info/<elementId>
Token: requer
Entrada:
{}Saída:
{ "status": true, "msg": "Dados obtidos com sucesso.", "element": { "element_id": 1, "element_name": "Ácido Clorídrico", "element_image": null, "element_molar_mass": "36.46", "element_quantity": "500.00", "element_cas_number": "7647-01-0", "element_ec_number": "231-595-7", "element_admin_level": "2", "element_validity": "2026-12-31T03:00:00.000Z", "element_physical_state": "Líquido", "lab_id": 1 } }Method:
PUT
Route:<api_ip>/elements/edit/name
Token: requer
Entrada:
{ "element_id": 1, "element_name": "Elemento x" }Saída:
{ "status": true, "msg": "Nome editado com sucesso." }Method:
PUT
Route:<api_ip>/elements/edit/quantity
Token: requer
Entrada:
{ "element_id": 1, "element_quantity": 100 }Saída:
{ "status": true, "msg": "Quantidade editada com sucesso." }Method:
PUT
Route:<api_ip>/elements/edit/cas
Token: requer
Entrada:
{ "element_id": 1, "element_cas_number": "1111-111" }Saída:
{ "status": true, "msg": "Número CAS editado com sucesso." }Method:
PUT
Route:<api_ip>/elements/edit/ec
Token: requer
Entrada:
{ "element_id": 1, "element_ec_number": "222-222-22" }Saída:
{ "status": true, "msg": "Número EC editado com sucesso." }Method:
PUT
Route:<api_ip>/elements/edit/state
Token: requer
Entrada:
{ "element_id": 1, "element_physical_state": "Sólido" }Saída:
{ "status": true, "msg": "Estado físico editado com sucesso." }Method:
PUT
Route:<api_ip>/elements/edit/validity
Token: requer
Entrada:
{ "element_id": 1, "element_validity": "2022-10-20" }Saída:
{ "status": true, "msg": "Validade editada com sucesso." }Method:
PUT
Route:<api_ip>/elements/edit/admin
Token: requer
Entrada:
{ "element_id": 1, "element_admin_level": 3 }Saída:
{ "status": true, "msg": "Responsável editado com sucesso." }Method:
PUT
Route:<api_ip>/elements/edit/molarmass
Token: requer
Entrada:
{ "element_id": 1, "element_molar_mass": 69 }Saída:
{ "status": true, "msg": "Massa molar editada com sucesso." }Method:
PUT
Route:<api_ip>/elements/edit/image
Token: requer
Entrada:
{ "element_id": 1, "element_image": "URI-IMAGE" }Saída:
{ "status": true, "msg": "Imagem editada com sucesso." }Method:
POST
Route:<api_ip>/equipments/register
Token: requer
Entrada:
{ "equipment_name": "Luneta", "equipment_quantity": 123, "equipment_quality": 5, "equipment_admin_level": 2, "equipment_image": "img", "lab_id": 1 }Saída:
{ "status": true, "msg": "Equipamento registrado com sucesso." }Method:
DELETE
Route:<api_ip>/equipments/delete
Token: requer
Entrada:
{ "equipment_id": 1 }Saída:
{ "status": true, "msg": "Equipamento deletado com sucesso." }Method:
GET
Route:<api_ip>/equipments/lab/<labId>
Token: requer
Entrada:
{}Saída:
{ "status": true, "msg": "Equipamentos encontrados.", "equipmentsList": [ { "equipmentId": 2, "name": "Centrífuga", "description": "Capacidade 12 tubos.", "quantity": 3, "quality": "4", "accessLevel": "2", "image": null, "labId": 1 } ] }Method:
GET
Route:<api_ip>/equipments/session/<labId>
Token: requer
Entrada:
{}Saída:
{ "status": true, "msg": "Equipamentos encontrados.", "equipmentsList": [ { "equipment_id": 2, "equipment_name": "Centrífuga", "equipment_description": "Capacidade 12 tubos.", "equipment_image": null, "total_quantity": 3, "reserved_quantity": 1, "equipment_quality": "4", "equipment_admin_level": "2", "lab_id": 1 } ] }Method:
GET
Route:<api_ip>/equipments/info/<equipmentId>
Token: requer
Entrada:
{}Saída:
{ "status": true, "msg": "Dados obtidos com sucesso.", "equipment": { "equipment_id": 2, "equipment_name": "Centrífuga", "equipment_description": "Capacidade 12 tubos.", "equipment_quantity": 3, "equipment_quality": "4", "equipment_admin_level": "2", "equipment_image": null, "lab_id": 1 } }Method:
PUT
Route:<api_ip>/equipments/edit/name
Token: requer
Entrada:
{ "equipment_name": "NACL - Sal de cozinha", "equipment_id": 2 }Saída:
{ "status": true, "msg": "Nome do equipamento editado com sucesso." }Method:
PUT
Route:<api_ip>/equipments/edit/quantity
Token: requer
Entrada:
{ "equipment_quantity": 69, "equipment_id": 2 }Saída:
{ "status": true, "msg": "Quantidade do equipamento editado com sucesso." }Method:
PUT
Route:<api_ip>/equipments/edit/quality
Token: requer
Entrada:
{ "equipment_quality": 1, "equipment_id": 2 }Saída:
{ "status": true, "msg": "Qualidade do equipamento editado com sucesso." }Method:
PUT
Route:<api_ip>/equipments/edit/description
Token: requer
Entrada:
{ "equipment_description": "é uma descrição muito completa", "equipment_id": 2 }Saída:
{ "status": true, "msg": "Descrição do equipamento editado com sucesso." }Method:
PUT
Route:<api_ip>/equipments/edit/admin
Token: requer
Entrada:
{ "equipment_admin_level": 3, "equipment_id": 2 }Saída:
{ "status": true, "msg": "Nível de administração do equipamento editado com sucesso." }Method:
PUT
Route:<api_ip>/equipments/edit/image
Token: requer
Entrada:
{ "equipment_image": "URI-IMAGE", "equipment_id": 2 }Saída:
{ "status": true, "msg": "Imagem do equipamento editado com sucesso." }Method:
POST
Route:<api_ip>/sessions/create
Token: requer
Entrada:
{ "lab_id": 1, "session_date": "2025-11-09", "session_starts_at": "16:00", "session_ends_at": "17:00", "elements_list": [ { "element_id": 5 } ], "equipments_list": [ { "equipment_id": 2 } ] }Saída:
{ "status": true, "msg": "Sessão criada com sucesso." }Method:
DELETE
Route:<api_ip>/sessions/delete
Token: requer
Entrada:
{ "session_id": 13 }Saída:
{ "status": true, "msg": "Sessão deletada com sucesso." }Method:
PUT
Route:<api_ip>/sessions/start
Token: requer
Entrada:
{ "session_id": 13 }Saída:
{ "status": true, "msg": "Sessão iniciada com sucesso." }Method:
PUT
Route:<api_ip>/sessions/finish
Token: requer
Entrada:
{ "session_id": 13 }Saída:
{ "status": true, "msg": "Sessão finalizada com sucesso." }Method:
GET
Route:<api_ip>/sessions/mysessions
Token: requer
Entrada:
{}Saída:
{ "status": true, "msg": "Sessões encontradas.", "sessionsList": [ { "sessionId": 3, "labName": "Lab Química A101", "date": "2025-09-03T03:00:00.000Z", "startsAt": "10:00:00", "endsAt": "12:00:00", "sessionStatus": "Finalizada", "elementsQtd": "30.00", "equipmentsQtd": "0", "formDone": 0 } ] }Method:
GET
Route:<api_ip>/sessions/form/<sessionId>
Token: requer
Entrada:
{}Saída:
{ "status": true, "msg": "Formulário encontrado.", "elements": [ { "element_id": 5, "element_name": "Cloreto de Sódio", "element_image": null, "element_molar_mass": "58.44", "reserved_quantity": "0.00", "element_cas_number": "7647-14-5", "element_ec_number": "231-598-3", "element_admin_level": "1", "element_validity": "2028-01-01T03:00:00.000Z", "element_physical_state": "Sólido", "lab_id": 1 } ] }Method:
PUT
Route:<api_ip>/sessions/form/set
Token: requer
Entrada:
{ "session_id": 13, "elements_list": [ { "element_id": 5, "element_quantity": 2 }, { "element_id": 2, "element_quantity": 5 }, { "element_id": 3, "element_quantity": 5 } ] }Saída:
{ "status": true, "msg": "Formulário salvo com sucesso." }


