Documentation Index
Fetch the complete documentation index at: https://mintlify.com/NicolasMPP/restorante-springboot/llms.txt
Use this file to discover all available pages before exploring further.
Restorante models every person in the system — whether an executive chef, a front-of-house server, a manager, or a dining guest — as a subtype of the Persona entity. Using JPA’s JOINED inheritance, the base identity fields (name, ID number, contact details) live in a single normalized personas table, while each role’s specialized data occupies its own joined table. This design avoids sparse columns and keeps identity queries clean, while still allowing each role to carry only the fields that make sense for it.
The Persona Base Class
Persona is the root of the hierarchy. It uses @Inheritance(strategy = InheritanceType.JOINED) — no discriminator column is present at this level, because JOINED inheritance uses the presence of a row in a subtype table to determine the concrete type.
@Entity
@Table(name = "personas")
@Inheritance(strategy = InheritanceType.JOINED)
public class Persona implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
protected Integer id;
@Column(name = "nombre", nullable = false, length = 100)
protected String nombre;
@Column(name = "cedula", nullable = false, unique = true, length = 20)
protected String cedula;
@Column(name = "telefono", length = 20)
protected String telefono;
@Column(name = "correo", length = 100)
protected String correo;
@Column(name = "usuario", length = 50)
protected String usuario;
@Column(name = "contrasenia", length = 100)
protected String contrasenia;
}
| Field | Type | Constraints |
|---|
id | Integer | Auto-generated primary key |
nombre | String | Not null, max 100 characters |
cedula | String | Not null, unique, 7–20 characters |
telefono | String | Optional, max 20 characters |
correo | String | Optional, max 100 characters |
usuario | String | Optional, max 50 characters |
contrasenia | String | Optional, max 100 characters |
The esValido() method on Persona enforces that nombre is non-blank and within 100 characters, and that cedula is non-blank and between 7 and 20 characters.
The Empleado Class
Empleado extends Persona and is stored in the empleados table, linked to personas by @PrimaryKeyJoinColumn(name = "id"). It introduces employment-specific fields and itself acts as the root of a nested SINGLE_TABLE hierarchy for employee subtypes (Chef and Mesero), using the tipo_empleado discriminator column.
@Entity
@Table(name = "empleados")
@PrimaryKeyJoinColumn(name = "id")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "tipo_empleado", discriminatorType = DiscriminatorType.STRING)
@DiscriminatorValue("EMPLEADO")
public class Empleado extends Persona implements Serializable {
@Column(name = "fecha_vinculacion")
protected LocalDate fechaVinculacion;
@Column(name = "hora_ingreso")
protected LocalDateTime horaIngreso;
@Column(name = "hora_salida")
protected LocalDateTime horaSalida;
@Column(name = "salario", precision = 10, scale = 2)
protected BigDecimal salario;
@JsonIgnore
@OneToMany(mappedBy = "chef", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private List<Receta> recetas = new ArrayList<>();
}
| Field | Type | Description |
|---|
fechaVinculacion | LocalDate | Date the employee joined |
horaIngreso | LocalDateTime | Start of the employee’s shift |
horaSalida | LocalDateTime | End of the employee’s shift |
salario | BigDecimal | Monthly salary (precision 10, scale 2) |
recetas | List<Receta> | Recipes authored by this employee (cascade ALL) |
The recetas relationship is defined on Empleado (not just on Chef) because the Receta entity’s chef field is typed as Empleado. This means any employee — including a Mesero, per the model — could technically be assigned a recipe, though in practice the API only assigns recipes through chef records.
Staff Roles at a Glance
| Role | Discriminator / Join | Table | Special Capabilities |
|---|
Gerente | JOINED (no discriminator) | gerentes | Owns Menu and Despensa via @OneToMany (cascade ALL) |
Chef | CHEF in tipo_empleado | empleados | Can be assigned Receta entities; looked up by cédula for recipe assignment |
Mesero | MESERO in tipo_empleado | empleados | Employee subtype; no dedicated API operations |
Cliente | JOINED (no discriminator) | clientes | Extends Persona only — no salary, schedule, or recipe relationships |
Gerente and Cliente both extend Persona directly using JOINED inheritance — they each have their own table (gerentes and clientes) with a @PrimaryKeyJoinColumn(name = "id"). Neither uses a discriminator column. Chef and Mesero, by contrast, extend Empleado and share the empleados table, differentiated only by the tipo_empleado discriminator value.
Seed Data
The InicializadorBD component seeds the following staff and client records on first startup. It checks personaRepository.count() > 0 before inserting, so the seed runs exactly once.
Gerente
Chefs
Mesero
Cliente
Gerente gerente = new Gerente(
"Martín Vargas", // nombre
"1234567890", // cedula
"2615488978", // telefono
"martinchef@itu.masterchef.com", // correo
"MChef55", // usuario
"Poo1234" // contrasenia
);
// Chef Andrés Martínez
chef.setNombre("Andrés Martínez");
chef.setCedula("2345678901");
chef.setCorreo("andyChef@itu.masterchef.com");
chef.setSalario(new BigDecimal("2500.00"));
chef.setFechaVinculacion(LocalDate.parse("2023-01-15"));
chef.setHoraIngreso(LocalDateTime.of(LocalDate.now(), LocalTime.parse("08:00:00")));
chef.setHoraSalida(LocalDateTime.of(LocalDate.now(), LocalTime.parse("16:00:00")));
// Chef Carina Sosa
chef.setNombre("Carina Sosa");
chef.setCedula("3456789012");
chef.setCorreo("carinaChef@itu.masterchef.com");
chef.setSalario(new BigDecimal("2800.00"));
chef.setFechaVinculacion(LocalDate.parse("2023-02-20"));
chef.setHoraIngreso(LocalDateTime.of(LocalDate.now(), LocalTime.parse("08:00:00")));
chef.setHoraSalida(LocalDateTime.of(LocalDate.now(), LocalTime.parse("16:00:00")));
mesero.setNombre("Ana Martínez");
mesero.setCedula("4567890123");
mesero.setCorreo("ana@restaurante.com");
mesero.setSalario(new BigDecimal("1800.00"));
mesero.setFechaVinculacion(LocalDate.parse("2023-03-10"));
mesero.setHoraIngreso(LocalDateTime.of(LocalDate.now(), LocalTime.parse("10:00:00")));
mesero.setHoraSalida(LocalDateTime.of(LocalDate.now(), LocalTime.parse("18:00:00")));
Cliente cliente = new Cliente(
"Pedro Sánchez", // nombre
"5678901234", // cedula
"555-0005", // telefono
"pedro@email.com" // correo
);
API Access by Role
Chefs are the only staff role with a dedicated REST endpoint at /api/chefs. This endpoint is used primarily to retrieve chef records for recipe assignment. All other staff roles are managed through their own repositories internally but do not expose a dedicated external endpoint in the current implementation.
When a food item is created or updated with a recipe, the API resolves the authoring chef by cédula — the chefCedula field in the request body is looked up against the cedula column in the empleados table (filtered to tipo_empleado = 'CHEF').
The chef’s cédula — not their database id — is the key used in the AlimentoCompletoRequest body when creating or updating a food item with a recipe. For example, to assign Chef Carina Sosa (cédula 3456789012) to a new Pasta Carbonara entry, include "chefCedula": "3456789012" in the request payload.