RELE · 05-data-model.md · 7 de 22

En esta página 1. Visión general 0%

05 — Modelo de datos — RELE

1. Visión general

Dominio mínimo de lecturas energéticas L2:

EntidadPropósito
UserIdentidad RESIDENT o ADVISOR
HomeVivienda del residente (label, address, CUPS)
ReadingLectura de contador por periodo con estado y notas

Base: PostgreSQL (Neon) · ORM: Prisma · IDs: cuid().

2. Enums

Role

ValorDescripción
RESIDENTTitular / habitante que registra lecturas
ADVISORAsesor que revisa y anota

ReadingStatus

ValorDescripción
DRAFTBorrador (reservado; no usado en create v1)
SUBMITTEDEnviada por residente (default create)
REVIEWEDRevisada OK por asesor
FLAGGEDMarcada para atención (tarifa / anomalía)

3. Diagrama ER (texto)

User
  id, email, passwordHash, name, role
  homes[] (RESIDENT)
  readings[] (como resident)
  reviews[] (como advisor)

Home
  id, label, address, cups
  residentId → User
  readings[]

Reading
  id, code (unique)
  period, kwh, costEur?, notes, advisorNote
  status (default SUBMITTED)
  homeId → Home
  residentId → User
  advisorId? → User
  createdAt, updatedAt

4. Tablas / modelos Prisma

User

CampoTipoConstraints
idStringPK, cuid
emailStringunique
passwordHashStringbcrypt
nameString
roleRoleRESIDENT | ADVISOR
createdAtDateTimedefault now
updatedAtDateTimeupdatedAt

Home

CampoTipoConstraints
idStringPK, cuid
labelStringej. “Piso Ruzafa”
addressString
cupsStringcódigo punto suministro (demo)
residentIdStringFK User
createdAtDateTime

Reading

CampoTipoConstraints
idStringPK, cuid
codeStringunique, formato RE-MMDD-XXX
periodStringej. 2026-08
kwhFloat≥ 0
costEurFloat?opcional
notesStringdefault ""
advisorNoteStringdefault ""
statusReadingStatusdefault SUBMITTED
homeIdStringFK Home
residentIdStringFK User
advisorIdString?FK User (advisor)
createdAt / updatedAtDateTime

5. Reglas de integridad y negocio

ReglaImplementación
Auth lecturasJwtAuthGuard en controller readings → 401 sin token
Create solo RESIDENTForbiddenException si no RESIDENT
Status solo ADVISORForbiddenException si no ADVISOR
Get RESIDENTSolo si reading.residentId === userId
Código únicocode unique; generación RE- + MMDD + random 100–999
Home en createPrimera home del residente o create default
NotesCoalesce a "" si omitidas
Orden listadocreatedAt desc
PasswordNunca en claro; solo passwordHash

6. Contratos API (resumen)

POST /api/auth/login

Body: { email, password }
Response 200:

{
  "accessToken": "<jwt>",
  "user": { "id": "...", "email": "...", "name": "...", "role": "RESIDENT" }
}

GET /api/readings (JWT)

Array Reading + includes (home, resident|advisor según rol).

GET /api/readings/stats/summary (JWT)

{
  "total": 5,
  "open": 3,
  "byStatus": {
    "DRAFT": 0,
    "SUBMITTED": 2,
    "REVIEWED": 2,
    "FLAGGED": 1
  },
  "kwhTotal": 921
}

open = SUBMITTED + FLAGGED.
kwhTotal = suma de kWh del scope del rol.

GET /api/readings/:id (JWT)

Reading con home + resident + advisor, o 404/403.

POST /api/readings (JWT RESIDENT)

Body

CampoTipoReq
periodstringsí (min 4)
kwhnumbersí ≥ 0
costEurnumberno
notesstringno
homeLabelstringno (solo si se crea home)

Response: Reading + home; status SUBMITTED.

PATCH /api/readings/:id/status (JWT ADVISOR)

Body: { status: ReadingStatus, advisorNote?: string }
Efecto: actualiza status, advisorId = me, advisorNote si se envía.

7. Seed de referencia

EntidadDatos
RESIDENTElena Marín · casa@rele.energy · password123
ADVISORToni Gil · asesor@rele.energy · password123
HomePiso Ruzafa · C/ Sueca 18, 3º · València · CUPS ES0021000000000001AB
RE-0809-012026-07 · 212 kWh · 48.6 € · REVIEWED
RE-0809-022026-06 · 168 kWh · 39.2 € · REVIEWED
RE-0809-032026-08 · 245 kWh · 56.1 € · SUBMITTED
RE-0809-042026-05 · 141 kWh · 33.4 € · FLAGGED
RE-0809-052026-04 · 155 kWh · 36.0 € · SUBMITTED

8. Índices y rendimiento (v1)

NecesidadEnfoque v1
List by residentwhere residentId (volumen demo bajo)
Unique codeconstraint unique Prisma
StatsgroupBy status + aggregate kwh

Índices adicionales (residentId, status) = L2+ si crece volumen.

9. Privacidad de campos

CampoSensibilidadQuién lo ve
emailPIIself + advisor en list
cupsidentificador suministroambos roles en scope
passwordHashsecretonunca en API response
advisorNotesemi-sensibleambos en detalle