05 — Modelo de datos — SURCO
1. Visión general
Dominio mínimo de cuaderno de campo L2:
| Entidad | Propósito |
|---|---|
| User | Identidad + rol FARMER | TECHNICIAN |
| Parcel | Bancal / parcela de la explotación del farmer |
| FieldTask | Tarea de campo con estado, vencimiento y asignación opcional |
Base: PostgreSQL (Neon) · ORM: Prisma · IDs: cuid().
2. Enums
Role
| Valor | Descripción |
|---|---|
FARMER | Titular / planificador; crea tareas y parcelas |
TECHNICIAN | Ejecutor de campo; ve asignaciones |
TaskStatus
| Valor | Descripción |
|---|---|
PENDING | Planificada; sin arrancar o sin técnico |
ACTIVE | En curso (p. ej. al asignar técnico) |
DONE | Completada |
CANCELLED | Anulada |
3. Diagrama ER (texto)
User ─────────────┬────────── Parcel
id │ id
email │ name
passwordHash │ crop
name │ hectares
role │ farmerId ──► User.id
│
├────────── FieldTask (as farmer)
│ id, code, title, notes
│ status, dueAt
│ farmerId ──► User.id
│ technicianId? ──► User.id
│ parcelId ──► Parcel.id
│
└────────── FieldTask (as technician)
4. Tablas / modelos Prisma
User
| Campo | Tipo | Constraints |
|---|---|---|
| id | String | PK, cuid |
| String | unique | |
| passwordHash | String | bcrypt |
| name | String | |
| role | Role | |
| createdAt | DateTime | default now |
| updatedAt | DateTime | updatedAt |
| parcels | Parcel[] | |
| tasksFarmer | FieldTask[] | rel “FarmerTasks” |
| tasksTech | FieldTask[] | rel “TechTasks” |
Parcel
| Campo | Tipo | Constraints |
|---|---|---|
| id | String | PK |
| name | String | nombre de bancal (no unique global; lookup por farmer+name) |
| crop | String | cultivo |
| hectares | Float | |
| farmerId | String | FK User |
| tasks | FieldTask[] | |
| createdAt | DateTime |
FieldTask
| Campo | Tipo | Constraints |
|---|---|---|
| id | String | PK |
| code | String | unique, formato SU-MMDD-XXX |
| title | String | |
| notes | String | default "" |
| status | TaskStatus | default PENDING |
| dueAt | DateTime | |
| farmerId | String | FK |
| technicianId | String? | FK opcional |
| parcelId | String | FK |
| createdAt / updatedAt | DateTime |
5. Reglas de integridad y negocio
| Regla | Implementación |
|---|---|
| Solo FARMER crea tareas | Controller: role check → 403 |
| Lista filtrada por rol | where farmerId o technicianId |
| Acceso a detalle | Mismas condiciones o 403 |
| Parcela al vuelo | findFirst name+farmer; else create |
| Técnico por email | User.role debe ser TECHNICIAN |
| Código único | unique en DB; generación en service |
| Password | Nunca en claro; solo passwordHash |
6. Seed de referencia (2026-08-07)
| Entidad | Datos |
|---|---|
| FARMER | Inés Roura · campo@surco.agro · password123 |
| TECHNICIAN | Pol Vidal · tecnico@surco.agro · password123 |
| Parcel 1 | Bancal Nord · Olivo arbequina · 2.4 ha |
| Parcel 2 | Surco Baix · Almendro · 1.1 ha |
| Tasks | 5 filas: riego ACTIVE, plagas PENDING, poda DONE, suelo PENDING, abonado ACTIVE |
Códigos ejemplo: SU-0807-01 … SU-0807-05 (el prefijo de fecha depende del día de seed).
7. Contratos API ↔ modelo
POST /api/auth/login
In: { email, password }
Out: { accessToken, user: { id, email, name, role } }
GET /api/tasks
Out: FieldTask[] con parcel, farmer, technician.
GET /api/tasks/stats/summary
Out:
{
"total": 5,
"open": 4,
"byStatus": { "PENDING": 2, "ACTIVE": 2, "DONE": 1, "CANCELLED": 0 }
}
POST /api/tasks
In:
{
"title": "Riego gota a gota",
"parcelName": "Bancal Nord",
"crop": "Olivo arbequina",
"dueAt": "2026-08-08T08:00:00.000Z",
"notes": "2 h sector A",
"technicianEmail": "tecnico@surco.agro"
}
Out: FieldTask creado (status ACTIVE si técnico OK).
PATCH /api/tasks/:id/status
In: { "status": "DONE" }
Out: FieldTask actualizado.
GET /api/tasks/:id
Out: un FieldTask con relaciones; 403/404 según acceso.
8. Índices y escalado (notas)
| Necesidad futura | Índice sugerido |
|---|---|
| Listas por farmer + due | (farmerId, dueAt) |
| Listas por tech + status | (technicianId, status) |
| Búsqueda por code | ya unique en code |
v1 no define índices extra más allá de PK/unique Prisma.
9. Privacidad de datos (enlace a doc 11)
- Email y nombre son datos de cuenta demo.
- Notas de tarea pueden contener info operativa de finca: no loguear bodies en claro en producción.
- No se almacenan coordenadas GPS ni datos de salud vegetal sensibles más allá de texto libre.
10. Criterios de aceptación de datos
- Migración
initaplica User, Parcel, FieldTask + enums. - Seed es idempotente en la práctica (
deleteMany+ create). - No se puede insertar
FieldTasksinparcelIdyfarmerIdválidos (FK). codeúnico impide colisiones exactas (retry no implementado; probabilidad baja con random 100–999).