20 — Implementación — RELE
1. Resumen ejecutivo técnico
| Campo | Valor |
|---|
| App path | /Users/cristian/orca/rele-app/ |
| GitHub | https://github.com/Criscode2022/rele-app |
| API | NestJS · puerto 3009 · prefijo /api |
| Web | Angular standalone · puerto 4200 |
| DB | Neon PostgreSQL · Prisma · sparkling-snow-59844541 |
| Auth | JWT Bearer · roles RESIDENT | ADVISOR |
| Dominio | User, Home, Reading |
| Fecha | 2026-08-09 |
| Case | /Users/cristian/orca/ux-projects/2026-08-09-rele/ |
2. Cómo arrancar
cd /Users/cristian/orca/rele-app
# Dependencias (apps independientes, sin workspaces)
npm install --prefix apps/api
npm install --prefix apps/web
# Entorno API: DATABASE_URL (Neon) + JWT_SECRET
# cp apps/api/.env.example apps/api/.env # si existe
npm --prefix apps/api run prisma:migrate
npm --prefix apps/api run prisma:seed
npm run api # Nest → http://localhost:3009
npm run web # Angular → http://localhost:4200
Credenciales
3. Módulos API implementados
Auth
POST /api/auth/login
- Valida email/password; compara bcrypt; emite JWT.
- Response:
{ accessToken, user: { id, email, name, role } }.
JwtStrategy + JwtAuthGuard protegen readings.
Readings
| Método | Ruta | Notas |
|---|
| GET | /api/readings | filtro por rol (resident propias / advisor todas) |
| GET | /api/readings/stats/summary | total, open, byStatus, kwhTotal |
| GET | /api/readings/:id | ownership check resident |
| POST | /api/readings | solo RESIDENT; home resolve/create; status SUBMITTED |
| PATCH | /api/readings/:id/status | solo ADVISOR; advisorId + advisorNote |
Prisma
Enums Role, ReadingStatus; modelos User, Home, Reading; seed 2 users + 1 home + 5 readings.
4. Frontend implementado
| Página | Path | Responsabilidad |
|---|
| HomePage | / | marketing, hero, pasos, CTAs rol |
| LoginPage | /login | form → ApiService.login → /lecturas |
| ReadingsPage | /lecturas | stats + list + empty/error + logout |
| ReadingNewPage | /lecturas/nueva | form create (resident) |
| ReadingDetailPage | /lecturas/:id | get + patch status (advisor) |
ApiService centraliza base URL http://localhost:3009/api, storage rele_token / rele_user, métodos HTTP tipados.
5. Decisiones de implementación
| Decisión | Razón |
|---|
| Puerto API 3009 | Evitar colisión con VOLTA 3008 / SURCO 3007 |
| Soft auth en páginas | Simple L2; API es autoridad |
| Create → SUBMITTED | Menos fricción que DRAFT |
| Home implícita en create | Menos pantallas CRUD L2 |
| open = SUBMITTED + FLAGGED | Ops de “requiere atención” |
| kwhTotal en stats | Dominio energía visible |
| Templates inline standalone | Velocidad daily |
| accessToken camelCase | Alineado serie (SURCO) |
6. Variables de entorno
| Variable | Servicio | Descripción |
|---|
DATABASE_URL | API | Neon connection string |
JWT_SECRET | API | Firma tokens |
PORT | API | opcional, 3009 |
Web: URL de API en apps/web/src/app/core/api.service.ts.
7. Smoke de implementación (mínimo)
- Seed OK en consola (
RELE seed OK).
- Login residente 200 +
accessToken.
- List length ≥ 1; stats con
kwhTotal.
- Create reading 200/201 · code
RE-… · SUBMITTED.
- Login asesor ve lecturas de Elena.
- Patch REVIEWED/FLAGGED 200.
- RESIDENT patch → 403; ADVISOR create → 403.
- Web muestra palette maritime + badges.
8. Estructura de ficheros clave
rele-app/
├── package.json
├── README.md
└── apps/
├── api/
│ ├── prisma/schema.prisma
│ ├── prisma/seed.ts
│ └── src/
│ ├── main.ts # port 3009, prefix api
│ ├── app.module.ts
│ ├── auth/
│ │ ├── auth.controller.ts
│ │ ├── auth.service.ts
│ │ ├── jwt.strategy.ts
│ │ └── jwt-auth.guard.ts
│ ├── readings/
│ │ ├── readings.controller.ts
│ │ ├── readings.service.ts
│ │ └── readings.module.ts
│ └── prisma/
└── web/
├── tailwind.config.js # fog/navy/sea/coral · Sora/Nunito
├── src/styles.css
└── src/app/
├── app.routes.ts
├── core/api.service.ts
└── pages/
├── home/home.page.ts
├── login/login.page.ts
├── readings/readings.page.ts
├── reading-new/reading-new.page.ts
└── reading-detail/reading-detail.page.ts
9. Tokens implementados (web)
| Token | Valor |
|---|
| bg | #EEF1F4 |
| ink | #0C2340 |
| sea | #2F8F8C |
| coral | #E07A5F |
| border | #D0D8E0 |
| display | Sora |
| sans | Nunito Sans |
10. Seed detallado
| Código | Periodo | kWh | € | Status | Nota asesor |
|---|
| RE-0809-01 | 2026-07 | 212 | 48.6 | REVIEWED | Pico coherente con ola de calor. |
| RE-0809-02 | 2026-06 | 168 | 39.2 | REVIEWED | Dentro de rango. |
| RE-0809-03 | 2026-08 | 245 | 56.1 | SUBMITTED | — |
| RE-0809-04 | 2026-05 | 141 | 33.4 | FLAGGED | Revisar tarifa PVPC vs fija. |
| RE-0809-05 | 2026-04 | 155 | 36.0 | SUBMITTED | — |
Home: Piso Ruzafa · C/ Sueca 18, 3º · València · CUPS ES0021000000000001AB.
11. Endpoints — tabla de contratos
| Método | Ruta | Auth | Body / notes |
|---|
| POST | /api/auth/login | No | { email, password } |
| GET | /api/readings | JWT | — |
| GET | /api/readings/stats/summary | JWT | — |
| GET | /api/readings/:id | JWT | — |
| POST | /api/readings | JWT RESIDENT | { period, kwh, costEur?, notes?, homeLabel? } |
| PATCH | /api/readings/:id/status | JWT ADVISOR | { status, advisorNote? } |
12. Paridad con Paper y case
| Artefacto | Ref |
|---|
| Paper | 01KZJNCCMJ1FDHHPZZ923RWDWY |
| Hero | assets/hero.jpg (case + web) |
| Docs | 2026-08-09-rele/docs/* |
| Executive | presentation/executive-summary.md |
13. Criterio de cierre implementación