Documentation Index
Fetch the complete documentation index at: https://docs.fitlocus.com/llms.txt
Use this file to discover all available pages before exploring further.
API de Relacionamento Personal-Aluno
A API de Relacionamento Personal-Aluno do FitLocus fornece endpoints para gerenciamento das conexões entre personal trainers e seus alunos na plataforma.
Visão Geral
A API de Relacionamento Personal-Aluno permite:
- Envio e gerenciamento de convites de personal trainers para alunos
- Aceitação ou recusa de convites por parte dos alunos
- Listagem de alunos vinculados a um personal trainer
- Listagem de personal trainers vinculados a um aluno
- Remoção de vínculos entre personal trainers e alunos
Modelo de Dados
PersonalStudentDTO
O objeto PersonalStudentDTO é utilizado para transferência de dados de relacionamentos entre personal trainers e alunos:
{
"id": 123,
"personalId": 456,
"personalName": "Carlos Oliveira",
"personalEmail": "[email protected]",
"personalProfilePicture": "https://storage.googleapis.com/fitlocus-app-50458.appspot.com/profile/456.jpg",
"studentId": 789,
"studentName": "João Silva",
"studentEmail": "[email protected]",
"studentProfilePicture": "https://storage.googleapis.com/fitlocus-app-50458.appspot.com/profile/789.jpg",
"status": "ACTIVE",
"createdAt": "2023-01-01T10:00:00Z",
"updatedAt": "2023-01-15T14:30:00Z"
}
InviteDTO
Objeto utilizado para envio de convites:
{
"id": 234,
"personalId": 456,
"personalName": "Carlos Oliveira",
"studentEmail": "[email protected]",
"message": "Olá João, gostaria de ser seu personal trainer no FitLocus.",
"status": "PENDING",
"createdAt": "2023-05-20T15:30:00Z",
"expiresAt": "2023-05-27T15:30:00Z"
}
Endpoints Principais
| Método | Endpoint | Descrição |
|---|
| POST | /personal/students/invite | Envia um convite para um aluno |
| GET | /personal/invites | Lista convites enviados pelo personal trainer |
| GET | /students/invites | Lista convites recebidos pelo aluno |
| POST | /students/invites/{id}/accept | Aceita um convite |
| POST | /students/invites/{id}/reject | Recusa um convite |
| GET | /personal/students | Lista alunos vinculados ao personal trainer |
| GET | /students/personals | Lista personal trainers vinculados ao aluno |
| DELETE | /personal/students/{id} | Remove vínculo com um aluno |
| DELETE | /students/personals/{id} | Remove vínculo com um personal trainer |
Detalhes de Implementação
Autenticação
Todos os endpoints requerem autenticação via token JWT no cabeçalho Authorization:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Para mais detalhes sobre autenticação, consulte a documentação de autenticação.
Controle de Acesso
O acesso aos endpoints é controlado com base no tipo de usuário:
- Endpoints com prefixo
/personal/ só podem ser acessados por usuários do tipo PERSONAL
- Endpoints com prefixo
/students/ só podem ser acessados por usuários do tipo ALUNO
- Verificações adicionais garantem que um usuário só possa acessar dados relacionados a si mesmo
Enviar Convite para Aluno
Endpoint
POST /personal/students/invite
Este endpoint permite que um personal trainer envie um convite para um aluno.
Cabeçalhos da Requisição
| Cabeçalho | Valor | Descrição |
|---|
| Authorization | Bearer | Token JWT do usuário |
| Content-Type | application/json | Tipo de conteúdo da requisição |
Parâmetros da Requisição
O corpo da requisição deve conter um objeto JSON com os seguintes campos:
| Campo | Tipo | Obrigatório | Descrição |
|---|
| studentEmail | string | Sim | Email do aluno |
| message | string | Não | Mensagem personalizada para o convite |
Exemplo de Requisição
curl -X POST \
'http://localhost:8080/api/personal/students/invite' \
-H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...' \
-H 'Content-Type: application/json' \
-d '{
"studentEmail": "[email protected]",
"message": "Olá João, gostaria de ser seu personal trainer no FitLocus."
}'
Resposta de Sucesso
Código: 201 Created
{
"id": 234,
"personalId": 456,
"personalName": "Carlos Oliveira",
"studentEmail": "[email protected]",
"message": "Olá João, gostaria de ser seu personal trainer no FitLocus.",
"status": "PENDING",
"createdAt": "2023-05-20T15:30:00Z",
"expiresAt": "2023-05-27T15:30:00Z"
}
Respostas de Erro
Código: 400 Bad Request
{
"message": "Validation failed",
"errors": [
{
"field": "studentEmail",
"message": "Email inválido"
}
],
"success": false
}
Código: 401 Unauthorized
{
"message": "Token inválido ou expirado",
"success": false
}
Código: 403 Forbidden
{
"message": "Apenas personal trainers podem enviar convites",
"success": false
}
Código: 404 Not Found
{
"message": "Usuário não encontrado com o email fornecido",
"success": false
}
Código: 409 Conflict
{
"message": "Já existe um convite pendente para este aluno",
"success": false
}
Código: 422 Unprocessable Entity
{
"message": "Você atingiu o limite de alunos para seu plano atual",
"success": false
}
Listar Convites Enviados
Endpoint
Este endpoint retorna uma lista paginada de convites enviados pelo personal trainer.
Parâmetros de Consulta
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|
| status | string | Não | Filtrar por status (PENDING, ACCEPTED, REJECTED, EXPIRED) |
| page | number | Não | Número da página (default: 0) |
| size | number | Não | Tamanho da página (default: 20) |
| sort | string | Não | Campo e direção de ordenação (ex: createdAt,desc) |
Cabeçalhos da Requisição
| Cabeçalho | Valor | Descrição |
|---|
| Authorization | Bearer | Token JWT do usuário |
Exemplo de Requisição
curl -X GET \
'http://localhost:8080/api/personal/invites?status=PENDING&page=0&size=10&sort=createdAt,desc' \
-H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'
Resposta de Sucesso
Código: 200 OK
{
"content": [
{
"id": 234,
"personalId": 456,
"personalName": "Carlos Oliveira",
"studentEmail": "[email protected]",
"message": "Olá João, gostaria de ser seu personal trainer no FitLocus.",
"status": "PENDING",
"createdAt": "2023-05-20T15:30:00Z",
"expiresAt": "2023-05-27T15:30:00Z"
},
// Mais convites...
],
"pageable": {
"sort": {
"sorted": true,
"unsorted": false,
"empty": false
},
"pageNumber": 0,
"pageSize": 10,
"offset": 0,
"paged": true,
"unpaged": false
},
"totalPages": 1,
"totalElements": 3,
"last": true,
"first": true,
"sort": {
"sorted": true,
"unsorted": false,
"empty": false
},
"number": 0,
"numberOfElements": 3,
"size": 10,
"empty": false
}
Respostas de Erro
Código: 401 Unauthorized
{
"message": "Token inválido ou expirado",
"success": false
}
Código: 403 Forbidden
{
"message": "Apenas personal trainers podem acessar este recurso",
"success": false
}
Listar Convites Recebidos
Endpoint
Este endpoint retorna uma lista paginada de convites recebidos pelo aluno.
Parâmetros de Consulta
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|
| status | string | Não | Filtrar por status (PENDING, ACCEPTED, REJECTED, EXPIRED) |
| page | number | Não | Número da página (default: 0) |
| size | number | Não | Tamanho da página (default: 20) |
| sort | string | Não | Campo e direção de ordenação (ex: createdAt,desc) |
Cabeçalhos da Requisição
| Cabeçalho | Valor | Descrição |
|---|
| Authorization | Bearer | Token JWT do usuário |
Exemplo de Requisição
curl -X GET \
'http://localhost:8080/api/students/invites?status=PENDING&page=0&size=10&sort=createdAt,desc' \
-H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'
Resposta de Sucesso
Código: 200 OK
{
"content": [
{
"id": 234,
"personalId": 456,
"personalName": "Carlos Oliveira",
"personalEmail": "[email protected]",
"personalProfilePicture": "https://storage.googleapis.com/fitlocus-app-50458.appspot.com/profile/456.jpg",
"message": "Olá João, gostaria de ser seu personal trainer no FitLocus.",
"status": "PENDING",
"createdAt": "2023-05-20T15:30:00Z",
"expiresAt": "2023-05-27T15:30:00Z"
},
// Mais convites...
],
"pageable": {
"sort": {
"sorted": true,
"unsorted": false,
"empty": false
},
"pageNumber": 0,
"pageSize": 10,
"offset": 0,
"paged": true,
"unpaged": false
},
"totalPages": 1,
"totalElements": 2,
"last": true,
"first": true,
"sort": {
"sorted": true,
"unsorted": false,
"empty": false
},
"number": 0,
"numberOfElements": 2,
"size": 10,
"empty": false
}
Respostas de Erro
Código: 401 Unauthorized
{
"message": "Token inválido ou expirado",
"success": false
}
Código: 403 Forbidden
{
"message": "Apenas alunos podem acessar este recurso",
"success": false
}
Aceitar Convite
Endpoint
POST /students/invites/{id}/accept
Este endpoint permite que um aluno aceite um convite de personal trainer.
Parâmetros de URL
| Parâmetro | Tipo | Descrição |
|---|
| id | number | ID do convite |
Cabeçalhos da Requisição
| Cabeçalho | Valor | Descrição |
|---|
| Authorization | Bearer | Token JWT do usuário |
Exemplo de Requisição
curl -X POST \
'http://localhost:8080/api/students/invites/234/accept' \
-H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'
Resposta de Sucesso
Código: 200 OK
{
"id": 123,
"personalId": 456,
"personalName": "Carlos Oliveira",
"personalEmail": "[email protected]",
"personalProfilePicture": "https://storage.googleapis.com/fitlocus-app-50458.appspot.com/profile/456.jpg",
"studentId": 789,
"studentName": "João Silva",
"studentEmail": "[email protected]",
"studentProfilePicture": "https://storage.googleapis.com/fitlocus-app-50458.appspot.com/profile/789.jpg",
"status": "ACTIVE",
"createdAt": "2023-05-20T15:35:00Z",
"updatedAt": "2023-05-20T15:35:00Z"
}
Respostas de Erro
Código: 401 Unauthorized
{
"message": "Token inválido ou expirado",
"success": false
}
Código: 403 Forbidden
{
"message": "Apenas alunos podem aceitar convites",
"success": false
}
Código: 403 Forbidden
{
"message": "Você não pode aceitar convites de outros usuários",
"success": false
}
Código: 404 Not Found
{
"message": "Convite não encontrado",
"success": false
}
Código: 409 Conflict
{
"message": "Este convite já foi processado ou expirou",
"success": false
}
Recusar Convite
Endpoint
POST /students/invites/{id}/reject
Este endpoint permite que um aluno recuse um convite de personal trainer.
Parâmetros de URL
| Parâmetro | Tipo | Descrição |
|---|
| id | number | ID do convite |
Cabeçalhos da Requisição
| Cabeçalho | Valor | Descrição |
|---|
| Authorization | Bearer | Token JWT do usuário |
Exemplo de Requisição
curl -X POST \
'http://localhost:8080/api/students/invites/234/reject' \
-H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'
Resposta de Sucesso
Código: 200 OK
{
"id": 234,
"personalId": 456,
"personalName": "Carlos Oliveira",
"studentEmail": "[email protected]",
"message": "Olá João, gostaria de ser seu personal trainer no FitLocus.",
"status": "REJECTED",
"createdAt": "2023-05-20T15:30:00Z",
"expiresAt": "2023-05-27T15:30:00Z",
"updatedAt": "2023-05-20T15:40:00Z"
}
Respostas de Erro
Código: 401 Unauthorized
{
"message": "Token inválido ou expirado",
"success": false
}
Código: 403 Forbidden
{
"message": "Apenas alunos podem recusar convites",
"success": false
}
Código: 403 Forbidden
{
"message": "Você não pode recusar convites de outros usuários",
"success": false
}
Código: 404 Not Found
{
"message": "Convite não encontrado",
"success": false
}
Código: 409 Conflict
{
"message": "Este convite já foi processado ou expirou",
"success": false
}
Listar Alunos do Personal Trainer
Endpoint
Este endpoint retorna uma lista paginada de alunos vinculados ao personal trainer.
Parâmetros de Consulta
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|
| name | string | Não | Filtrar por nome (busca parcial) |
| status | string | Não | Filtrar por status (ACTIVE, INACTIVE) |
| page | number | Não | Número da página (default: 0) |
| size | number | Não | Tamanho da página (default: 20) |
| sort | string | Não | Campo e direção de ordenação (ex: name,asc) |
Cabeçalhos da Requisição
| Cabeçalho | Valor | Descrição |
|---|
| Authorization | Bearer | Token JWT do usuário |
Exemplo de Requisição
curl -X GET \
'http://localhost:8080/api/personal/students?status=ACTIVE&page=0&size=10&sort=name,asc' \
-H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'
Resposta de Sucesso
Código: 200 OK
{
"content": [
{
"id": 123,
"personalId": 456,
"personalName": "Carlos Oliveira",
"studentId": 789,
"studentName": "João Silva",
"studentEmail": "[email protected]",
"studentProfilePicture": "https://storage.googleapis.com/fitlocus-app-50458.appspot.com/profile/789.jpg",
"status": "ACTIVE",
"createdAt": "2023-05-20T15:35:00Z",
"updatedAt": "2023-05-20T15:35:00Z"
},
// Mais alunos...
],
"pageable": {
"sort": {
"sorted": true,
"unsorted": false,
"empty": false
},
"pageNumber": 0,
"pageSize": 10,
"offset": 0,
"paged": true,
"unpaged": false
},
"totalPages": 1,
"totalElements": 5,
"last": true,
"first": true,
"sort": {
"sorted": true,
"unsorted": false,
"empty": false
},
"number": 0,
"numberOfElements": 5,
"size": 10,
"empty": false
}
Respostas de Erro
Código: 401 Unauthorized
{
"message": "Token inválido ou expirado",
"success": false
}
Código: 403 Forbidden
{
"message": "Apenas personal trainers podem acessar este recurso",
"success": false
}
Listar Personal Trainers do Aluno
Endpoint
Este endpoint retorna uma lista paginada de personal trainers vinculados ao aluno.
Parâmetros de Consulta
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|
| name | string | Não | Filtrar por nome (busca parcial) |
| status | string | Não | Filtrar por status (ACTIVE, INACTIVE) |
| page | number | Não | Número da página (default: 0) |
| size | number | Não | Tamanho da página (default: 20) |
| sort | string | Não | Campo e direção de ordenação (ex: name,asc) |
Cabeçalhos da Requisição
| Cabeçalho | Valor | Descrição |
|---|
| Authorization | Bearer | Token JWT do usuário |
Exemplo de Requisição
curl -X GET \
'http://localhost:8080/api/students/personals?status=ACTIVE&page=0&size=10&sort=name,asc' \
-H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'
Resposta de Sucesso
Código: 200 OK
{
"content": [
{
"id": 123,
"personalId": 456,
"personalName": "Carlos Oliveira",
"personalEmail": "[email protected]",
"personalProfilePicture": "https://storage.googleapis.com/fitlocus-app-50458.appspot.com/profile/456.jpg",
"studentId": 789,
"studentName": "João Silva",
"status": "ACTIVE",
"createdAt": "2023-05-20T15:35:00Z",
"updatedAt": "2023-05-20T15:35:00Z"
},
// Mais personal trainers...
],
"pageable": {
"sort": {
"sorted": true,
"unsorted": false,
"empty": false
},
"pageNumber": 0,
"pageSize": 10,
"offset": 0,
"paged": true,
"unpaged": false
},
"totalPages": 1,
"totalElements": 2,
"last": true,
"first": true,
"sort": {
"sorted": true,
"unsorted": false,
"empty": false
},
"number": 0,
"numberOfElements": 2,
"size": 10,
"empty": false
}
Respostas de Erro
Código: 401 Unauthorized
{
"message": "Token inválido ou expirado",
"success": false
}
Código: 403 Forbidden
{
"message": "Apenas alunos podem acessar este recurso",
"success": false
}
Endpoint
DELETE /personal/students/{id}
Este endpoint permite que um personal trainer remova o vínculo com um aluno.
Parâmetros de URL
| Parâmetro | Tipo | Descrição |
|---|
| id | number | ID do relacionamento personal-aluno |
Cabeçalhos da Requisição
| Cabeçalho | Valor | Descrição |
|---|
| Authorization | Bearer | Token JWT do usuário |
Exemplo de Requisição
curl -X DELETE \
'http://localhost:8080/api/personal/students/123' \
-H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'
Resposta de Sucesso
Código: 204 No Content
Respostas de Erro
Código: 401 Unauthorized
{
"message": "Token inválido ou expirado",
"success": false
}
Código: 403 Forbidden
{
"message": "Apenas personal trainers podem acessar este recurso",
"success": false
}
Código: 403 Forbidden
{
"message": "Você não pode remover vínculos de outros personal trainers",
"success": false
}
Código: 404 Not Found
{
"message": "Relacionamento não encontrado",
"success": false
}
Endpoint
DELETE /students/personals/{id}
Este endpoint permite que um aluno remova o vínculo com um personal trainer.
Parâmetros de URL
| Parâmetro | Tipo | Descrição |
|---|
| id | number | ID do relacionamento personal-aluno |
Cabeçalhos da Requisição
| Cabeçalho | Valor | Descrição |
|---|
| Authorization | Bearer | Token JWT do usuário |
Exemplo de Requisição
curl -X DELETE \
'http://localhost:8080/api/students/personals/123' \
-H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'
Resposta de Sucesso
Código: 204 No Content
Respostas de Erro
Código: 401 Unauthorized
{
"message": "Token inválido ou expirado",
"success": false
}
Código: 403 Forbidden
{
"message": "Apenas alunos podem acessar este recurso",
"success": false
}
Código: 403 Forbidden
{
"message": "Você não pode remover vínculos de outros alunos",
"success": false
}
Código: 404 Not Found
{
"message": "Relacionamento não encontrado",
"success": false
}
Implementação no Frontend
Componente de Envio de Convite
// Exemplo de componente de envio de convite em React
import React, { useState } from 'react';
import axios from 'axios';
const InviteForm = () => {
const [invite, setInvite] = useState({
studentEmail: '',
message: ''
});
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
const [success, setSuccess] = useState(false);
const handleChange = (e) => {
const { name, value } = e.target;
setInvite(prev => ({
...prev,
[name]: value
}));
};
const handleSubmit = async (e) => {
e.preventDefault();
// Validação básica
if (!invite.studentEmail) {
setError('Email do aluno é obrigatório');
return;
}
setLoading(true);
setError(null);
setSuccess(false);
try {
const response = await axios.post('/personal/students/invite', invite);
setLoading(false);
setSuccess(true);
// Resetar formulário
setInvite({
studentEmail: '',
message: ''
});
} catch (err) {
setLoading(false);
setError(err.response?.data?.message || 'Erro ao enviar convite');
}
};
return (
<div className="invite-form">
<h2>Convidar Aluno</h2>
{error && <div className="error-message">{error}</div>}
{success && <div className="success-message">Convite enviado com sucesso!</div>}
<form onSubmit={handleSubmit}>
<div className="form-group">
<label>Email do Aluno *</label>
<input
type="email"
name="studentEmail"
value={invite.studentEmail}
onChange={handleChange}
required
/>
</div>
<div className="form-group">
<label>Mensagem</label>
<textarea
name="message"
value={invite.message}
onChange={handleChange}
placeholder="Opcional: Adicione uma mensagem personalizada ao convite"
/>
</div>
<button type="submit" disabled={loading}>
{loading ? 'Enviando...' : 'Enviar Convite'}
</button>
</form>
</div>
);
};
export default InviteForm;
Componente de Listagem de Alunos
// Exemplo de componente de listagem de alunos em React
import React, { useEffect, useState } from 'react';
import axios from 'axios';
const StudentList = () => {
const [students, setStudents] = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
const [filters, setFilters] = useState({
name: '',
status: 'ACTIVE',
page: 0,
size: 10,
sort: 'name,asc'
});
useEffect(() => {
const fetchStudents = async () => {
try {
setLoading(true);
// Construir query string a partir dos filtros
const queryParams = new URLSearchParams();
if (filters.name) queryParams.append('name', filters.name);
if (filters.status) queryParams.append('status', filters.status);
queryParams.append('page', filters.page.toString());
queryParams.append('size', filters.size.toString());
queryParams.append('sort', filters.sort);
const response = await axios.get(`/personal/students?${queryParams.toString()}`);
setStudents(response.data.content);
setLoading(false);
} catch (err) {
setError(err.response?.data?.message || 'Erro ao carregar alunos');
setLoading(false);
}
};
fetchStudents();
}, [filters]);
const handleFilterChange = (e) => {
const { name, value } = e.target;
setFilters(prev => ({
...prev,
[name]: value,
page: 0 // Reset page when filters change
}));
};
const handleRemoveStudent = async (id) => {
if (!window.confirm('Tem certeza que deseja remover este aluno?')) {
return;
}
try {
await axios.delete(`/personal/students/${id}`);
// Atualizar lista de alunos
setStudents(prev => prev.filter(student => student.id !== id));
} catch (err) {
alert(err.response?.data?.message || 'Erro ao remover aluno');
}
};
if (loading) return <div>Carregando...</div>;
if (error) return <div>Erro: {error}</div>;
return (
<div className="student-list">
<h2>Meus Alunos</h2>
<div className="filters">
<input
type="text"
name="name"
placeholder="Buscar por nome"
value={filters.name}
onChange={handleFilterChange}
/>
<select
name="status"
value={filters.status}
onChange={handleFilterChange}
>
<option value="ACTIVE">Ativos</option>
<option value="INACTIVE">Inativos</option>
<option value="">Todos</option>
</select>
</div>
{students.length === 0 ? (
<p className="no-students">Nenhum aluno encontrado.</p>
) : (
<div className="student-grid">
{students.map(student => (
<div key={student.id} className="student-card">
<img
src={student.studentProfilePicture || '/default-avatar.png'}
alt={student.studentName}
className="profile-picture"
/>
<h3>{student.studentName}</h3>
<p className="email">{student.studentEmail}</p>
<p className="since">Desde: {new Date(student.createdAt).toLocaleDateString()}</p>
<div className="actions">
<button className="view-details">Ver Detalhes</button>
<button
className="remove"
onClick={() => handleRemoveStudent(student.id)}
>
Remover
</button>
</div>
</div>
))}
</div>
)}
<div className="pagination">
<button
disabled={filters.page === 0}
onClick={() => setFilters(prev => ({ ...prev, page: prev.page - 1 }))}
>
Anterior
</button>
<span>Página {filters.page + 1}</span>
<button
disabled={students.length < filters.size}
onClick={() => setFilters(prev => ({ ...prev, page: prev.page + 1 }))}
>
Próxima
</button>
</div>
</div>
);
};
export default StudentList;
Considerações de Design
A interface de gerenciamento de relacionamentos personal-aluno do FitLocus segue as diretrizes de design da plataforma:
- Cores: Fundo escuro (#202020), elementos de destaque em verde (#B4ED00), texto em branco (#F9F9F9)
- Tipografia: Hanken Grotesk para texto e SUPERINE para títulos
- Layout: Design minimalista com espaçamento generoso e hierarquia clara
- Componentes: Campos de formulário com bordas arredondadas, botões com feedback visual ao interagir
Para mais detalhes sobre o design, consulte as diretrizes de marca.
Considerações de Segurança
-
Validação de Dados: Todos os dados de entrada são validados tanto no frontend quanto no backend para prevenir injeção de dados maliciosos.
-
Controle de Acesso: Verificações rigorosas garantem que um usuário só possa acessar e modificar seus próprios relacionamentos.
-
Sanitização de Dados: Todos os dados de entrada são sanitizados antes de serem armazenados ou exibidos.
-
HTTPS: Todas as comunicações com a API devem ser realizadas através de HTTPS para proteger dados sensíveis durante a transmissão.
-
Limites de Plano: O sistema verifica se o personal trainer atingiu o limite de alunos do seu plano atual antes de permitir novos convites.
Regras de Negócio
-
Limites de Alunos por Plano:
- Plano Básico: até 5 alunos
- Plano Intermediário: até 15 alunos
- Plano Avançado: até 30 alunos
- Plano Premium: ilimitado
-
Expiração de Convites: Convites não aceitos expiram automaticamente após 7 dias.
-
Restrições de Vínculo: Um aluno pode ter múltiplos personal trainers, mas cada relacionamento é gerenciado independentemente.
-
Notificações: O sistema envia notificações por email quando:
- Um convite é enviado
- Um convite é aceito ou recusado
- Um vínculo é removido