# Caso receptor vs docente — briefing para revisión

Fecha: **2026-08-31**. Solo lectura: describe el modelo **real** (migraciones +
servicios + UI), no el de `docs/DECISION-MULTISEDE.md` (ese doc está
**obsoleto** en docentes/estudiantes; ver `CLAUDE.md` del backend).

**Pregunta de producto que hay que cerrar con Claude:** ¿está bien que el
receptor no se maneje como el docente? En particular, ¿qué pasa si al
siguiente ciclo esa persona trabaja en otra sede?

Esto **no es un plan de implementación**. No hay código que cambiar hasta
que se decida si el modelo actual es la regla de negocio correcta.

---

## 1. Intención de producto (TutorTrack)

TutorTrack digitaliza la tutoría (acompañamiento personal, no académico).
Cuando hay señal de alerta, el docente **deriva** al estudiante a una
oficina de la Facultad (psicología / salud). Esa oficina es la **entidad
receptora**. El **receptor** es el personal de esa oficina que atiende el
caso.

La derivación va a **una oficina de una sede**, no a un pool global de
personas.

---

## 2. Tres capas (igual para docente y receptor)

No se pisan:

| Capa | Dónde | Qué es |
|------|--------|--------|
| Identidad | `users` | Una fila por documento. Nombres, correo, acceso global (`users.active`). |
| Perfil / membresía | `teachers` / `students` / `receivers` | El “oficio”. |
| Rol (menú) | Spatie en **Usuarios** | `docente_tutor` / `estudiante` / `receptor`. Crear el perfil **no** asigna el rol. |

`link_existing`: si el documento ya existe y no tiene ese perfil, el alta
pide confirmación y **adjunta** el perfil sin sobrescribir identidad.

---

## 3. Modelo real hoy (código, no el doc viejo)

### Docente (y estudiante) — uno por persona; sede = actividad

Revertido el 2026-08-07 (`8d5f9ab`): **no** hay `campus_id` en el perfil.

- `teachers.user_id` único. Una persona = un perfil docente.
- Sede **derivada** de `cycle_period_teachers` → `cycle_periods.campus_id`.
- Alta: puede existir **sin sede** (“Sin sede — sin actividad asignada”).
- Listado docentes tiene filtro: *Con actividad* / *Todos los de la sede*.
- Dictar en las dos sedes = **el mismo perfil** + asignaciones a
  ciclo-períodos de cada sede. No se duplica el docente.

Estudiante: análogo, sede vía `enrollments` → `cycle_periods`.

### Receptor — N por persona; sede = entidad

Esto **no se revirtió**. Sigue el diseño “membresía a oficina”:

- `receiving_entities`: catálogo **por sede** (`campus_id` NOT NULL, unique
  `(campus_id, code)` y `(campus_id, name)`). Cada campus tiene su propia
  oficina de psicología/salud.
- `receivers`: unique `(user_id, receiving_entity_id)`. Soft delete.
  `receivers.active` existe en BD; **la UI de edición no lo usa** (el
  toggle visible es `users.active`, acceso global).
- Sede del receptor = `receiving_entities.campus_id` (HasOneThrough).
- Alta: **obligatorio** elegir entidad de la sede activa. La sede en el
  formulario es solo lectura.
- Listado: siempre filtrado por entidades de la sede activa. **No** hay
  filtro “con actividad” (no hay actividad académica que esperar).
- La misma persona puede tener **varias** filas `receivers` (una por
  oficina). Login: `User::allowedCampuses()` une las sedes de esas
  entidades; si hay más de una, sale el selector de sede.

Fuentes: `database/migrations/2026_07_31_100000_create_teachers_table.php`,
`2026_07_31_100002_create_receivers_table.php`,
`2026_07_30_220003_create_receiving_entities_table.php`,
`app/Services/TeacherService.php`, `app/Services/ReceiverService.php`,
`app/Models/User.php` (`allowedCampuses`),
`tutor-web/src/features/profiles/ProfilesPage.tsx`.

### `DECISION-MULTISEDE.md` — qué ignorar

Ese doc (2026-08-05) pedía perfil docente/estudiante **por sede**
(`campus_id` en `teachers`/`students`). Se implementó y se revirtió.
**No usarlo como spec.** El único tramo que sigue vigente para receptor
es: entidad por sede + membresía `(user_id, receiving_entity_id)`.

---

## 4. Comparación directa

| | Docente | Receptor |
|---|---|---|
| Perfiles por persona | 1 | 1 por entidad |
| Dónde vive la sede | Asignación a ciclo-período (después del alta) | Entidad receptora (en el alta) |
| Relación con el ciclo académico | Sí: dicta en un `cycle_period` | **Ninguna.** El ciclo no lo mueve. |
| Alta sin sede | Sí | No (hay que elegir entidad) |
| Trabajar en las dos sedes | Mismo perfil + dos asignaciones | Dos membresías (dos filas `receivers`) |
| “Trasladar” a otra sede editando el perfil | No aplica (la sede no está en el perfil) | **Bloqueado:** al actualizar, la entidad nueva debe ser de la sede activa, y el perfil actual también. |

---

## 5. Qué pasa si el próximo ciclo trabaja en otra sede

El ciclo **no hace nada** solo. No hay job, ni matrícula, ni reasignación
automática.

**No se edita** el perfil de Abancay para ponerle la entidad de
Tambobamba. `ReceiverService::update` exige:

1. El perfil actual sea de la sede activa (`assertSameCampus`).
2. La entidad nueva pertenezca a la sede activa.

Operar en ABA no puede “mover” el perfil a una entidad de TAM.

### Camino soportado: sumar membresía

1. Selector de sede → Tambobamba.
2. **Receptores → Agregar**, mismo documento, entidad de TAM.
3. Al Guardar, 409 si la persona ya existe → confirmar adjuntar perfil
   (`link_existing`). O desde **Usuarios** → agregar perfil receptor
   (`?document_type_id=&document_number=&link=1`).
4. Quedan dos filas `receivers`. Al login, elige sede.

Los casos viejos siguen en la oficina de ABA. Los nuevos de TAM van a la
entidad de TAM.

Derivación (`ReferralService::create`): el docente elige **entidad de la
sede activa**; `receiver_id` (especialista) es opcional pero, si viene,
**tiene que ser de esa misma entidad**. No se puede asignar un receptor
de TAM a un caso de ABA.

### Si dejó Abancay (ya no atiende ahí)

- El alta en TAM igual (sumar membresía).
- Quitar la membresía de ABA: `DELETE /receivers/{id}` (soft). **409** si
  `referrals.receiving_entity_id` de **esa entidad** tiene **cualquier**
  derivación — el bloqueo es a nivel **entidad**, no “si este receptor
  tiene casos asignados”. Mensaje:
  `messages.profiles.receiver_in_use`.
- `users.active` (CON ACCESO / SIN ACCESO) apaga **todo el sistema** para
  esa persona, las dos sedes a la vez.
- `receivers.active` (membresía) **no tiene UI**. No hay interruptor
  “ya no atiende en esta oficina”.

---

## 6. Huecos / olores (para que Claude los vea, no para “arreglar ya”)

1. **Baja de membresía vs historial.** Si la oficina de ABA ya tiene
   casos, no se puede borrar el perfil receptor aunque esa persona se
   haya ido. Queda membresía + puede seguir eligiendo esa sede al login.
2. **El 409 de delete es grueso.** Bloquea si la *entidad* tiene
   derivaciones, aunque este `receiver_id` no esté en ningún caso
   (`receiver_id` en `referrals` es nullable; muchos casos pueden ir
   solo a la entidad). Comentario en `ReceiverController::destroy`.
3. **No hay “traslado” ni “vigencia por período”.** La regla implícita
   es: o atiende en esa oficina, o no. El calendario académico no aplica.
4. **Rol `receptor` es global** (Spatie). Con dos membresías, el mismo
   rol vale en las dos sedes; el scope lo da `X-Campus-Id` + entidad.

Ninguno de estos es un bug de aislamiento de sede. Son límites de
producto.

---

## 7. Por qué no copiar el molde docente

Si el receptor fuera “uno por persona, sede derivada de actividad”:

- ¿Cuál sería la “actividad”? No dicta ciclo-período.
- Las derivaciones apuntan a **entidad**, no a un pool de personas. El
  especialista, si se elige, debe ser de esa oficina.
- Un psicólogo itinerante “como docente” rompería “el caso va a la
  oficina de esta sede”.

El modelo actual es coherente **si** la regla de la Facultad es: el
receptor es personal de una oficina, y la oficina es de una sede.

---

## 8. Preguntas para Claude (cerrar regla de negocio)

No implementar nada hasta responder esto:

1. ¿Un receptor que el próximo ciclo atiende en la otra sede se
   **suma** (dos oficinas a la vez, o transitorio las dos) o se
   **traslada** (deja de ser de ABA)?
2. Si se trasladó, ¿los casos abiertos de ABA siguen viéndolo / debe
   poder entrar a ABA solo a cerrarlos / un compañero de ABA los toma?
3. ¿Hace falta `receivers.active` en la UI (“ya no atiende aquí”) sin
   apagar el acceso global?
4. ¿El 409 al borrar debe ser “esta persona tiene casos asignados” en
   vez de “la entidad tiene derivaciones”?
5. ¿Puede la misma persona ser docente **y** receptor? Hoy el modelo de
   identidad lo permite (`link_existing` entre perfiles distintos). ¿Es
   deseable?

Si la respuesta a (1) es “sumar membresía, casos viejos en la oficina
vieja”, **no hay que cambiar código**. El camino ya existe.

Si es “traslado con vigencia por período, como el docente”, **sí** es
cambio de producto (esquema + UI + derivaciones) y hay que armar plan
aparte; no unificar a ciegas con `teachers`.
