00-day-brief.md
Abrir documentoDay brief — 2026-08-08 — ALS-2
1. LOAD — restricciones del día
| Eje | Decisión | Motivo (diversidad) |
|---|---|---|
| Complejidad | Nivel 1 | Tras SURCO (L2 agro multi-rol) se baja a L1 compacto: un rol autenticado + flujo público de solicitud. Craft no baja (D-P0-01). |
| Sector | Fitness comunitario / club de barrio | No usado en la serie (COMAL cocina, ATRIO museo, MERIDIANA clínica, SENDA mayores, FIRME legal, TROCHA logística, CORREA mascotas, SURCO agro). |
| Tipo de producto | Web club + solicitud de plaza + panel coach JWT | Cara pública + lead/request + inbox ops; no marketplace, no ERP, no flota. |
| Auth | JWT coach (rol COACH) | Directiva D-P1-05: panel no abierto; solicitud pública sin cuenta. |
| Craft mínimo | ≥ SURCO densificado en docs + Paper | L1 = menos módulos, no menos profundidad. |
| Cierre | §1.1 completo en una iteración | Docs + Paper + app + Neon + smoke; sin “próximos pasos del L1 del día”. |
| Puerto API | 3008 | Evitar colisión con SURCO (3007) y anteriores. |
Anti-patrones a evitar (top del catálogo)
| ID | Anti-patrón | Mitigación hoy |
|---|---|---|
| AP-thin-docs | Docs de 1–2 líneas | Suite 00–20 con tablas, AC y criterios de aceptación |
| AP-generic-ui | UI “SaaS genérico” / “básica porque L1” | Palette chalk × ink × lime; Syne + Work Sans |
| AP-no-auth | Panel sin login | JWT obligatorio en GET/PATCH requests |
| AP-marketplace-copy | Lógica de marketplace / checkout | No catálogo de pagos, no ratings, no matching multi-proveedor |
| AP-fake-research | Estadísticas inventadas como primarias | Solo hipótesis y supuestos etiquetados |
| AP-open-debt | Backlog de features del L1 del día | Vertical slice cerrado: home, join, success, login, inbox, detail |
| AP-canvas-chaos | Paper sin bandas § | §1 UX · §2 DS+Public · §3 Coach · §4 Mobile · §5 States |
| AP-agro-logistics-legal | Reutilizar dominio de días previos | Fitness club de barrio; ClassRequest + ClassType |
Barra de calidad actual (ratchet)
- Paper: bandas §1–§5, ≥8 artboards UX densos + DS + público + coach + mobile + states.
- Angular alineado a tokens (chalk/ink/lime; no default Tailwind genérico).
- API Nest + Prisma + Neon con seed demo usable (5 ClassRequest + coach).
- Smoke: POST público request + login coach + list + patch status;
ng buildo serve OK. - Docs en español, profundidad tipo portfolio (no stubs).
2. BRIEF — concepto del día
| Campo | Valor |
|---|---|
| Nombre | VOLTA |
| Eslogan | ”Tu plaza en la cancha.” |
| Una frase | Web del club de barrio para apuntarse a clases y panel JWT del coach que gestiona solicitudes de plaza. |
| Tipo | Web club + solicitud pública + inbox coach — Nivel 1 |
| Roles | Público (sin cuenta) · COACH (Nora Beltrán) |
| Dominio | User (COACH) + ClassRequest (NEW | CONTACTED | CONFIRMED | CANCELLED) + ClassType HIIT | YOGA | BASKET | KIDS | OPEN |
| Estilo | Chalk #F7F7F2 × Ink #0B0B0B × Lime #C6F23A × muted #5C5C58 × border #E2E2DC |
| Tipo | Syne (display) + Work Sans (UI) |
| Stack | Angular + NestJS + Prisma + Neon + Tailwind + JWT |
| Paper | https://app.paper.design/file/01KZG2VRQFF2QF0PRDB10D4AG7 |
| Neon | delicate-mountain-11765167 · API :3008 · Web :4200 |
| App | /Users/cristian/orca/volta-app/ · GitHub Criscode2022/volta-app (puede estar pendiente de push) |
Por qué L1 fitness (y no otra cosa)
- Diversidad de sector: la serie no había tocado club deportivo / fitness comunitario.
- Complejidad L1 justa: un rol autenticado, entidad core con máquina de estados, form público y panel ops — vertical slice denso sin multi-rol ni multi-tenant.
- Diferenciación vs CORREA: CORREA es marketplace B2C con reservas; VOLTA es lead de plaza del propio club (no matching de terceros).
- Diferenciación vs SURCO: SURCO es tool multi-rol de finca; VOLTA es web de club + inbox de solicitudes.
- Metáfora de marca: volta = vuelta / vuelta a la cancha; promesa de hueco real en el grupo, no de “app fitness genérica”.
Must-have del día (alcance L1)
| # | Entrega | Criterio done |
|---|---|---|
| 1 | Home marketing | Hero real, clases, horarios teaser, CTA apuntarme, footer demo |
| 2 | Formulario pública | POST /api/requests sin auth; validación campos |
| 3 | Success | Confirmación + código VO-… |
| 4 | Login JWT coach | coach@volta.club / password123 |
| 5 | Inbox + stats | Lista + summary; chips de estado |
| 6 | Detalle + PATCH status | NEW → CONTACTED → CONFIRMED / CANCELLED |
| 7 | Empty / error | Sin solicitudes; fallo de red en inbox |
| 8 | Paper §1–§5 | UX process + DS + público + coach + mobile + states |
| 9 | Docs 00–20 + README + executive | Portfolio ES, sin stubs |
Explicitamente fuera de alcance (no son deuda del día)
- Pagos / cuotas / Stripe
- Calendario de plazas en tiempo real / aforo live
- App nativa / wearables
- Multi-coach / multi-sede / multi-tenant
- Notificaciones email/SMS/WhatsApp automáticas
- Marketplace de entrenadores externos
- Perfil de socio completo / CRM pesado
3. Directivas activas aplicadas
| ID | Aplicación en VOLTA |
|---|---|
| D-P0-01 | L1 no reduce craft ni profundidad de docs |
| D-P0-02 | Hi-fi con media real (assets/hero.jpg), microcopy club |
| D-P0-03 | Angular + Nest + Neon + Tailwind + repo app |
| D-P0-04 | Canvas Paper en bandas §1–§5 con labels |
| D-P0-05 | Hero fotorrealista en case y app |
| D-P0-06 | Cierre §1.1 sin backlog del alcance L1 |
| D-P1-01 | ≥8 artboards UX en Paper (stakeholders → datos) |
| D-P1-02 | Tokens chalk/ink/lime en Angular |
| D-P1-03 | apps/api + apps/web independientes |
| D-P1-05 | JWT en GET/PATCH requests coach |
| D-P1-06 | Smoke public POST + login + list + patch |
4. Cuentas demo
| Rol | Nombre | Password | |
|---|---|---|---|
| COACH | Nora Beltrán | coach@volta.club | password123 |
Seed de referencia: 5 ClassRequest con códigos VO-0808-01…05 (HIIT NEW, YOGA CONTACTED, BASKET NEW, KIDS CONFIRMED, OPEN CANCELLED).
Supuestos (no investigación primaria)
- Clubs de barrio coordinan listas de espera y plazas por WhatsApp y papel en el mostrador.
- El coach necesita un inbox ordenado, no un ERP de socios.
- El visitante quiere pedir plaza sin crear cuenta ni app.
5. Criterio de cierre del día
- Brief de diversidad y anti-patrones documentado
- Producto definido (no marketplace, no agro, no logistics)
- Implementación runnable API :3008 / web :4200
- Documentación portfolio 00–20 + presentation + README
- Paper file enlazado y referenciado por bandas
- Hipótesis vs investigación marcadas (sin stats falsas)
Estado del brief: listo para EXECUTE y entrega de caso.
00-paper-reference.md
Abrir documentoReferencia Paper — VOLTA
| Campo | Valor |
|---|---|
| File ID | 01KZG2VRQFF2QF0PRDB10D4AG7 |
| URL | https://app.paper.design/file/01KZG2VRQFF2QF0PRDB10D4AG7 |
| Nombre | VOLTA — Daily UX 2026-08-08 |
| Producto | Web club + solicitud de plaza + panel coach JWT (L1) |
| Artboards | ~22 (+ labels de banda) |
| Bandas | §1 UX · §2 Design + Public · §3 Coach · §4 Mobile · §5 States |
| Idioma UI | es-ES |
| Media | assets/hero.jpg (cancha / club de barrio) |
1. Mapa de canvas (bandas jerárquicas)
| § | Banda | Propósito | Artboards clave |
|---|---|---|---|
| 1 | UX PROCESS | Investigación y modelo de servicio (densidad visual) | Cover, Stakeholders, Personas, JTBD, Journey, Blueprint, IA, Datos |
| 2 | DESIGN + PUBLIC | Sistema visual y cara pública | Design System, Home, Join form, Success |
| 3 | COACH | Flujos autenticados desktop/tablet | Login, Inbox, Request detail |
| 4 | MOBILE | Móvil visitante y coach en vestuario | Join / Inbox mobile |
| 5 | STATES | Resiliencia UI | Empty inbox, Error red |
Layout canvas (referencia): origen (0,0) · gaps ~80px · bandas Y orientativas: UX ~100 / Design ~2180 / Coach ~3980 / Mobile ~4880 / States ~5680.
2. Inventario de artboards
§1 — UX PROCESS
| Label | Nombre | Contenido |
|---|---|---|
| 1-0 | §1 UX PROCESS | Etiqueta de banda |
| 2-0 | UX-00 Cover | Portada VOLTA, eslogan, fecha 2026-08-08, L1 fitness, roles, dark ink + lime |
| 3-0 | UX-01 Stakeholders | Mapa interés/influencia: socio potencial, coach, familia, sede, ayuntamiento (bajo) |
| 4-0 | UX-02 Personas | Marc Solé (visitante) · Nora Beltrán (COACH) — goals, pains, quote |
| 5-0 | UX-03 JTBD | Job principal + funcional/emocional/social + MoSCoW / stories Must |
| 6-0 | UX-04 Journey | 5 fases visitante: descubre → elige clase → pide plaza → espera contacto → confirma |
| 7-0 | UX-05 Blueprint | Frontstage web · backstage coach · sistemas · fallos red/estado |
| 8-0 | UX-06 IA | Sitemap público/auth; navegación y permisos |
| 9-0 | UX-07 Datos | ERD: User, ClassRequest + enums Role, RequestStatus, ClassType |
§2 — DESIGN + PUBLIC
| Label | Nombre | Contenido |
|---|---|---|
| A-0 | §2 DESIGN + PUBLIC | Etiqueta de banda |
| B-0 | 00 Design System | Color chalk/ink/lime, tipo Syne+Work Sans, botones, badges estado, cards |
| C-0 | 01 Home | Nav, hero + media, clases, horarios teaser, CTAs, footer demo |
| D-0 | 02 Join | Form solicitud: nombre, email, teléfono, tipo, día, franja, notas |
| E-0 | 03 Success | Confirmación + código VO-… + próximos pasos |
§3 — COACH (desktop)
| Label | Nombre | Contenido |
|---|---|---|
| F-0 | §3 COACH | Etiqueta de banda |
| G-0 | 04 Login | Split dark/form; email/password; contexto panel coach |
| H-0 | 05 Inbox | Lista + stats summary; badge COACH; filtros visuales por estado |
| I-0 | 06 Detail | Código VO-…, contacto, clase, preferencias, chips estado, acciones |
§4 — MOBILE
| Label | Nombre | Contenido |
|---|---|---|
| J-0 | §4 MOBILE | Etiqueta de banda |
| K-0 | 07 Mobile Join / Inbox | Vista ~390px; touch targets ≥44px |
§5 — STATES
| Label | Nombre | Contenido |
|---|---|---|
| L-0 | §5 STATES | Etiqueta de banda |
| M-0 | 08 Empty | Inbox sin solicitudes; copy orientativo |
| N-0 | 09 Error | Fallo de carga / red; mensaje accionable + reintento |
3. Checklist de densidad (anti thin-frames)
| Criterio | §1 UX | §2 DS/Public | §3–4 Coach | §5 States |
|---|---|---|---|---|
| Jerarquía tipográfica visible | Sí | Sí | Sí | Sí |
| Microcopy real (no lorem) | Sí | Sí | Sí | Sí |
| Tokens de color aplicados | — | Sí | Sí | Sí |
| Datos de seed creíbles | Personas | Demo emails | Códigos VO-… | Empty realista |
| Media / iconografía | Cover | Hero | Badges | Alertas |
4. Mapeo Paper → Angular
| Artboard | Ruta app | Componente |
|---|---|---|
| C-0 Home | / | HomePage |
| D-0 Join | /apuntarme | JoinPage |
| E-0 Success | /ok | SuccessPage |
| G-0 Login | /login | LoginPage |
| H-0 Inbox | /inbox | InboxPage |
| I-0 Detail | /inbox/:id | RequestDetailPage |
| K-0 Mobile | mismas rutas, viewport estrecho | responsive |
| M-0 Empty | /inbox (0 items) | empty state en lista |
| N-0 Error | inbox / detalle | mensajes error en páginas |
5. Tokens de diseño en Paper
| Token | Valor | Uso |
|---|---|---|
| Chalk / bg | #F7F7F2 | Fondo de página |
| Surface | #FFFFFF | Cards, header |
| Ink | #0B0B0B | Primary dark, CTAs, texto fuerte |
| Lime | #C6F23A | Acento marca, highlights, CTAs lime |
| Lime soft | #EAF8B8 | Fondos suaves / badges |
| Lime strong | #A8D420 | Hover lime |
| Muted | #5C5C58 | Texto secundario |
| Border | #E2E2DC | Bordes de card y inputs |
| Display | Syne | H1–H2, logo wordmark |
| UI | Work Sans | Body, labels, botones |
Nota implementación:
tailwind.config.jsde la app usa los mismos hex de marca;primarymapea a ink para CTAs dark;limepara acentos.
6. Enlaces
- Paper: https://app.paper.design/file/01KZG2VRQFF2QF0PRDB10D4AG7
- Case:
/Users/cristian/orca/ux-projects/2026-08-08-volta/ - App:
/Users/cristian/orca/volta-app/ - Neon project:
delicate-mountain-11765167
01-project-definition.md
Abrir documento01 — Definición de proyecto — VOLTA
1. Identidad
| Campo | Valor |
|---|---|
| Nombre | VOLTA |
| Significado | Vuelta a la cancha: el hueco que te espera en el grupo del barrio |
| Eslogan | ”Tu plaza en la cancha.” |
| Una frase | Web del club de barrio para pedir plaza en clases y panel del coach que gestiona esas solicitudes. |
| Sector | Fitness comunitario / club de barrio |
| Tipo | Web club + solicitud pública + inbox coach JWT — Nivel 1 |
| Plataforma | Web responsive (móvil-first visitante + desktop coach) |
| Mercado demo | España (club de barrio, Valencia en copy) |
| Idioma | es-ES |
| Fecha caso | 2026-08-08 |
2. Problema
Principal (hipótesis de diseño)
Los clubs de barrio gestionan listas de plaza por WhatsApp, notas en el mostrador y mensajes perdidos. El visitante no sabe si su mensaje llegó; el coach no tiene un inbox con estado (nuevo / contactado / confirmado).
Secundarios
| Problema | Quién lo sufre | Efecto |
|---|---|---|
| “Apúntame al HIIT del jueves” en hilos | Visitante | No hay acuse ni código de referencia |
| Listas en papel / Excel local | Coach | Difícil priorizar contactos del día |
| Sin tipo de clase ni franja preferida | Ambos | Llamadas de ida y vuelta |
| Sin máquina de estados | Coach | Se pierde quién ya fue contactado |
Supuestos (no investigación primaria propia)
- S1: Clubs pequeños–medianos no necesitan un CRM enterprise; sí un inbox de solicitudes con estado.
- S2: El visitante prefiere un form de 1 pantalla a crear cuenta o descargar app.
- S3: El valor inmediato está en captura estructurada + pipeline de estado, no en aforo live ni pagos.
Hipótesis de producto
| ID | Hipótesis | Señal de validación (futura) |
|---|---|---|
| H1 | Un form público con tipo de clase y franja reduce mensajes ambiguos | ↓ “¿a qué hora?” post-solicitud |
| H2 | Inbox con estados NEW→CONTACTED→CONFIRMED acelera el cierre de plaza | Mediana tiempo NEW→CONFIRMED |
| H3 | Códigos cortos VO-MMDD-XXX facilitan referencia oral | Uso del código en WhatsApp/llamada |
No se afirman estadísticas de mercado inventadas. Todo lo anterior es razonamiento de diseño etiquetado.
3. Propuesta de valor
| Para | Valor |
|---|---|
| Visitante (Marc) | Pide plaza en 1 minuto: clase, día y franja sin cuenta. |
| Coach (Nora) | Ve solicitudes nuevas, marca contacto y confirma o cancela. |
| Club | Canal digital mínimo viable sin marketplace ni ERP de socios. |
No es VOLTA
| Excluido | Por qué |
|---|---|
| Marketplace de entrenadores o clubs | Eso sería CORREA-like; no es el club propio |
| Tool de finca / logística / legal | Dominios de otros días de la serie |
| SaaS multi-sede con billing | Complejidad L3/L4 |
| App fitness con wearables / planes IA | Fuera del job “plaza en la cancha” |
4. Objetivos
Negocio / caso de estudio
- Demostrar vertical slice L1 fitness con JWT coach y dominio ClassRequest.
- Portfolio coherente: Paper + docs + app runnable.
Usuario
| Rol | Objetivo medible en demo |
|---|---|
| Visitante | Enviar solicitud en < 2 min; ver código en success |
| Coach | Marcar CONTACTED / CONFIRMED en < 3 taps desde el inbox |
No objetivos v1 (explícitos)
- Pagos y cuotas mensuales
- Aforo en tiempo real por clase
- Chat in-app
- Multi-coach con permisos granulares
- Export contable
5. Roles y permisos (resumen)
| Acción | Público | COACH |
|---|---|---|
| Ver home / clases | Sí | Sí |
| POST solicitud | Sí | Sí (mismo form) |
| Login JWT | No (no cuenta socio) | Sí |
| Listar solicitudes | No (401) | Sí |
| Ver stats summary | No | Sí |
| Ver detalle | No | Sí |
| Cambiar status | No | Sí |
6. Métricas (modelo, no instrumentadas en v1 salvo base)
| Tipo | Métrica | Definición |
|---|---|---|
| North Star | Solicitudes CONFIRMED / semana | Plazas realmente cerradas |
| Activación | 1ª solicitud pública | POST create |
| Ops | % NEW contactadas en 24 h | NEW → CONTACTED |
| Calidad | Tasa error API en create/list | 4xx/5xx |
| UX | Tiempo form complete | Mediana en analytics futuro |
7. Alcance funcional v1 (L1)
| Módulo | Incluido |
|---|---|
| Home pública | Hero, clases, horarios teaser, CTAs |
| Solicitud | Form + POST /api/requests |
| Success | Código + mensaje |
| Auth | POST /api/auth/login → JWT |
| Inbox | GET list, GET stats, GET by id, PATCH status |
| UI estados | Loading implícito, empty, error de red |
| Seed | 1 coach, 5 solicitudes |
8. Criterios de aceptación de producto
- Un visitante puede enviar una solicitud sin autenticación y recibir un código
VO-…. - Sin token, GET/PATCH
/api/requests*responden 401. - Un coach puede iniciar sesión y ver el inbox ordenado (createdAt desc) con stats.
- El detalle permite transicionar estados NEW | CONTACTED | CONFIRMED | CANCELLED.
- La home comunica club de barrio y plaza, no marketplace ni gym chain genérico.
- Tipos de clase soportados: HIIT, YOGA, BASKET, KIDS, OPEN.
9. Stack y artefactos
| Capa | Detalle |
|---|---|
| Frontend | Angular + Tailwind · puerto 4200 |
| Backend | NestJS · puerto 3008 |
| DB | Neon PostgreSQL · Prisma · project delicate-mountain-11765167 |
| Auth | JWT (passport/strategy en API) |
| Diseño | Paper 01KZG2VRQFF2QF0PRDB10D4AG7 |
| Repo app | /Users/cristian/orca/volta-app/ · GitHub Criscode2022/volta-app |
10. Riesgos y mitigaciones
| Riesgo | Impacto | Mitigación v1 |
|---|---|---|
| Spam en form público | Inbox ruidoso | Validación server; honeypot futuro L1+ |
| Expectativa de aforo live | Decepción | Copy “solicitud”; coach confirma |
| Confundir con ClassPass | Expectativa marketplace | Marca club único, no multi-sede |
| PII en solicitudes | Privacidad | Solo coach autenticado lista; doc 11 |
11. Glosario
| Término | Definición en VOLTA |
|---|---|
| Plaza | Hueco en una clase o cancha abierta del club |
| Solicitud | ClassRequest con preferencias y estado |
| Coach | Usuario autenticado que opera el inbox |
| Código VO- | Identificador corto oral (VO-0808-01) |
| OPEN | Tipo de clase “cancha abierta” / libre |
02-ux-research-strategy.md
Abrir documento02 — Estrategia de investigación UX — VOLTA
Importante: este documento contiene artefactos de diseño y razonamiento secundario.
No hay entrevistas de campo primarias ni estadísticas inventadas presentadas como dato medido.
Etiquetas: [COMPROBADO] en producto, [SUPUESTO], [HIPÓTESIS], [DECISIÓN DE DISEÑO].
1. Objetivos de investigación (del caso)
| Objetivo | Método en este caso | Salida |
|---|---|---|
| Entender actores del club de barrio | Modelado de stakeholders + personas | §3–4 |
| Definir job principal | JTBD + stories Must | §5 |
| Mapear fricción de plaza | Journey + service blueprint | §6–7 |
| Traducir a requisitos L1 | Matriz hallazgo → requisito → feature | §8 |
2. Fuentes y límites
Fuentes admisibles (secundarias / operativas)
- Conocimiento general de clubs deportivos de barrio y gestión informal de listas.
- Analogía operativa con captación de leads + inbox ops (serie daily: paneles JWT, estados).
- Restricciones ALS-2 de diversidad (sector fitness libre; no marketplace; no agro/legal/logistics).
Límites éticos de verdad
| Prohibido | Permitido |
|---|---|
| “El 68% de clubs usa solo WhatsApp” sin fuente | “[SUPUESTO] la coordinación informal es frecuente en clubs pequeños” |
| Citas de usuarios ficticios como entrevistas reales | Quotes de persona etiquetadas como constructo de diseño |
| NPS inventado | Hipótesis H1–H3 con métrica futura |
3. Stakeholders
| Stakeholder | Influencia | Interés | Necesidad principal |
|---|---|---|---|
| Socio potencial / visitante | Baja formal | Muy alta | Pedir plaza sin fricción |
| Coach del club (COACH) | Alta | Muy alta | Inbox ordenado y estados |
| Familia (inscripción KIDS) | Media | Alta | Datos de contacto claros |
| Junta / dueño del club | Alta adopción | Media | Menos caos operativo |
| Ayuntamiento / instalaciones | Baja en v1 | Baja | Fuera de producto |
| Apps marketplace fitness | Competencia | — | No copiar modelo multi-proveedor |
Mapa de poder (resumen)
- Decisor de adopción: coach / responsable del club.
- Usuario frecuente captura: visitante (form) y coach (inbox diario).
- Riesgo de rechazo: si el form pide más que un WhatsApp sin devolver acuse ni claridad de estado.
4. Personas
P1 — Marc Solé · Visitante / socio potencial
| Campo | Detalle |
|---|---|
| Edad / contexto | ~28 años; quiere HIIT o cancha por la tarde tras el trabajo |
| Digital | Alta; móvil-first; odia crear cuentas para “solo preguntar” |
| Goals | Saber que su plaza está pedida; recibir contacto del club |
| Pains | Mensajes sin respuesta; no sabe a quién escribir; horarios confusos |
| Quote de diseño | “Dime la clase, el día y que alguien me conteste.” |
| Seed demo | marc@example.com · solicitud HIIT VO-0808-01 |
Escenario: Entra en la web del club, elige HIIT 19:00, envía y guarda el código VO-.
P2 — Nora Beltrán · COACH
| Campo | Detalle |
|---|---|
| Edad / contexto | ~35 años; coach y cara del club de barrio |
| Digital | Media–alta; usa móvil entre clases y desktop en la oficina |
| Goals | Ver nuevas solicitudes, contactar, confirmar o cancelar plazas |
| Pains | WhatsApp mezclado con personal; no sabe quién ya fue llamado |
| Quote de diseño | “Si está en NEW, es mío. Si está CONFIRMED, hay plaza.” |
| Email demo | coach@volta.club |
Escenario: Login → inbox → Marc NEW → CONTACTED → tras llamada CONFIRMED.
Anti-persona
| Quién | Por qué no es target v1 |
|---|---|
| Cadena de gimnasios multi-ciudad con CRM y billing | Necesita multi-sede, cuotas, aforo live → L3/L4 |
| Marketplace de coaches freelancers | Producto tipo CORREA, no club propio |
5. JTBD y user stories
Job principal (visitante)
Cuando quiero un hueco en una clase o cancha del club,
quiero enviar mis datos y preferencias en un solo paso,
para que el coach me contacte sin perder el mensaje en WhatsApp.
Job principal (coach)
Cuando llegan pedidos de plaza,
quiero verlos con estado y tipo de clase,
para contactar y confirmar sin Excel ni papel.
Jobs secundarios
| Job | Rol |
|---|---|
| Ver cuántas abiertas (NEW+CONTACTED) hay | COACH |
| Referir una solicitud por código corto | Ambos |
| Cancelar si no hay hueco o no contesta | COACH |
Stories Must (v1)
| ID | Story | AC |
|---|---|---|
| US1 | Como visitante, quiero un form con tipo de clase, día y franja | POST 201 + redirect success |
| US2 | Como visitante, quiero un código de referencia | code visible en /ok |
| US3 | Como coach, quiero entrar con email/password | JWT + redirect /inbox |
| US4 | Como coach, quiero listar solicitudes y stats | GET list + summary |
| US5 | Como coach, quiero cambiar estado | PATCH status |
MoSCoW (v1)
| Prioridad | Ítems |
|---|---|
| Must | Home, join, success, login, inbox, detail, status, empty/error |
| Should | Labels ES de ClassType y status; badges de color |
| Could | Filtro por status en UI; copy teléfono click-to-call |
| Won’t | Pagos, aforo live, multi-coach, notificaciones push |
6. Journey (visitante → coach)
| Fase | Actor | Acción | Touchpoint | Emoción [HIPÓTESIS] |
|---|---|---|---|---|
| 1 Descubrir | Marc | Entra a web | Home hero | Curiosidad |
| 2 Elegir | Marc | Mira clases | Sección #clases | Interés |
| 3 Pedir | Marc | Rellena form | /apuntarme | Esperanza |
| 4 Acuse | Marc | Ve código | /ok | Alivio |
| 5 Contacto | Nora | Ve NEW, llama | Inbox + detalle | Control |
| 6 Cierre | Nora | CONFIRMED | PATCH | Satisfacción operativa |
Momentos de verdad
- Form sin cuenta — si pide login, abandono alto [HIPÓTESIS].
- Código VO- — prueba social de “ha llegado”.
- Estado en inbox — evita re-contactar a quien ya está confirmado.
7. Service blueprint (resumen)
| Capa | Elementos |
|---|---|
| Frontstage visitante | Home, form, success |
| Frontstage coach | Login, inbox, detail, botones estado |
| Backstage | Coach llama/WhatsApp externo (fuera de app) |
| Sistemas | Nest API, Prisma, Neon, JWT, Angular |
| Soportes | Seed demo, Paper, docs |
| Fallos | 401 sin token; 404 id; red caída → UI error |
8. Matriz hallazgo → requisito → feature
| Hallazgo | Tipo | Requisito | Feature v1 |
|---|---|---|---|
| Mensajes ambiguos sin clase/hora | [SUPUESTO] | Capturar ClassType + day + slot | Form join |
| Sin acuse al visitante | [HIPÓTESIS] | Devolver código | Success + code |
| Coach no sabe estado | [SUPUESTO] | Máquina de estados | RequestStatus |
| Panel abierto = riesgo PII | [DECISIÓN] | Auth JWT | Login + guards API |
| L1 compacto | [DECISIÓN] | Un rol COACH | Sin multi-rol |
9. Preguntas abiertas (no bloquean v1)
| ID | Pregunta | Cómo se resolvería después |
|---|---|---|
| Q1 | ¿Aforo real por franja? | Integración calendario L2+ |
| Q2 | ¿Email automático al coach? | Hook post-create L1+ |
| Q3 | ¿RGPD consent explícito en form? | Checkbox + política L1+ |
10. Síntesis
VOLTA se diseña como canal de plaza del club, no como marketplace fitness.
La investigación del caso es constructiva y etiquetada: personas, JTBD y journey son artefactos de diseño; las métricas de validación quedan para uso real futuro.
03-information-architecture.md
Abrir documento03 — Arquitectura de información — VOLTA
1. Principios de IA
| Principio | Aplicación |
|---|---|
| Plaza primero | CTA dominante “Apuntarme” / “Quiero una plaza” en home |
| Público vs coach | Form abierto; inbox solo autenticado |
| Pocos niveles | Público (3) + Coach (3) — profundidad máx. 2 clicks a detalle |
| Lenguaje de dominio | Plaza, clase, franja, solicitud — no “ticket”, “lead CRM”, “order” |
| Código visible | VO-… en success e inbox para referencia oral |
2. Sitemap
/ Home (público)
/apuntarme Formulario de plaza (público)
/ok Success post-solicitud (público)
/login Login JWT coach
/inbox Lista + stats (auth COACH)
/inbox/:id Detalle + estado (auth COACH)
/** → redirect /
Árbol por audiencia
| Audiencia | Nodos relevantes |
|---|---|
| Visitante | Home → Apuntarme → Ok |
| Coach | Login → Inbox → Detail |
| Ambos | Home (coach link en nav) |
3. Navegación
Pública
| Elemento | Destino | Notas |
|---|---|---|
| Wordmark VOLTA | / | Display Syne, extrabold |
| Clases | #clases | Ancla home |
| Horarios | #horarios | Ancla home |
| Coach | /login | Entrada panel |
| Apuntarme | /apuntarme | Primary CTA (ink × lime text) |
Coach (autenticado)
| Elemento | Destino | Visibilidad |
|---|---|---|
| Wordmark / Inbox | /inbox | COACH |
| Badge rol | — | COACH |
| Nombre usuario | — | COACH |
| Salir | limpia token → /login | COACH |
| Card solicitud | /inbox/:id | COACH |
| Volver (detalle) | /inbox | COACH |
No hay menú lateral multi-sección en v1 (evita IA de CRM).
4. Inventario de contenido
| Pantalla | Contenidos |
|---|---|
| Home | Eyebrow “CLUB DE BARRIO · VALENCIA”, H1 eslogan, lead, CTAs, 3 stats teaser, hero img, grid clases, horarios, footer demo |
| Join | Título, campos form, submit, link atrás |
| Success | Mensaje OK, código, siguiente paso (te contactamos) |
| Login | Título panel coach, email, password, submit, error |
| Inbox | Stats (total, open, byStatus), lista cards, empty, error |
| Detail | Meta código/tipo, contacto, preferencias, notas, acciones estado |
5. Taxonomía y etiquetas
RequestStatus
| Status API | Label UI | Semántica |
|---|---|---|
NEW | Nueva | Acaba de llegar; sin contacto |
CONTACTED | Contactada | Coach ha hablado / escrito |
CONFIRMED | Confirmada | Plaza cerrada |
CANCELLED | Cancelada | Sin hueco / desiste / no contesta |
Orden de lista: por createdAt descendente (más reciente primero).
ClassType
| API | Label UI sugerido | Notas |
|---|---|---|
HIIT | HIIT | Alta intensidad |
YOGA | Yoga | Suave / movilidad |
BASKET | Basket | Cancha / equipo |
KIDS | Kids | Infantil |
OPEN | Cancha abierta | Libre / OPEN |
6. Modelo mental vs UI
| Modelo mental del usuario | Representación |
|---|---|
| “Apuntarme al grupo” | Form /apuntarme |
| “Me dieron un número de referencia” | code VO- |
| “Lista del día de gente nueva” | Inbox + badge NEW |
| “Ya le llamé” | Status CONTACTED |
| “Tiene plaza” | Status CONFIRMED |
7. Rutas API alineadas a IA
| UI | API |
|---|---|
| Submit join | POST /api/requests |
| Login | POST /api/auth/login |
| Inbox list | GET /api/requests |
| Stats | GET /api/requests/stats/summary |
| Detail | GET /api/requests/:id |
| Cambiar estado | PATCH /api/requests/:id/status |
8. Decisiones de IA descartadas
| Idea | Por qué no en L1 |
|---|---|
| Área de socio con historial | Multi-sesión y cuenta pública |
| Calendario semanal interactivo | Aforo live = L2+ |
| Chat coach–socio in-app | Fuera job mínimo |
| Nested nav “CRM → Leads → …” | Sobre-arquitectura |
04-user-flows.md
Abrir documento04 — Flujos de usuario — VOLTA
Convenciones
- Actor: Guest | COACH
- Éxito: resultado observable
- Errores: UI + código HTTP cuando aplica
F1 — Descubrimiento (Guest)
Home (/) → anclas #clases / #horarios
→ CTA "Quiero una plaza" | "Apuntarme"
→ /apuntarme
→ (nav) "Coach" → /login
| Paso | Acción | Sistema |
|---|---|---|
| 1 | Lee valor, clases y horarios teaser | Render estático |
| 2 | Click CTA plaza | Router → /apuntarme |
| 3 | Opcional: coach entra al panel | Router → /login |
Éxito: form de plaza o login visible.
F2 — Solicitar plaza (Guest, público)
/apuntarme → validación cliente
→ POST /api/requests { fullName, email, phone?, classType, preferredDay, preferredSlot, notes? }
→ 201 ClassRequest { code, ... }
→ /ok (state o query con code)
| Campo | Validación cliente (mín.) | API |
|---|---|---|
| fullName | required, min 2 | @MinLength(2) |
| required, email | @IsEmail() | |
| phone | optional | @IsOptional() |
| classType | enum HIIT…OPEN | @IsEnum(ClassType) |
| preferredDay | required (date string) | @MinLength(4) |
| preferredSlot | required | @MinLength(2) |
| notes | optional | default "" |
Éxito: registro status=NEW, código VO-MMDD-XXX, pantalla success.
Errores:
| Caso | Comportamiento |
|---|---|
| Validación DTO | 400 + mensaje form |
| Red caída | Error de red en UI form |
| Email mal formado | 400 |
No hay cuenta de socio en v1.
F3 — Success (Guest)
/ok → muestra copy de confirmación + code
→ CTA volver home o "seguir explorando"
| Paso | Acción | Sistema |
|---|---|---|
| 1 | Lee acuse | UI |
| 2 | Copia mental del código | — |
| 3 | Espera contacto del club | Fuera de app (WhatsApp/llamada) |
F4 — Login JWT (COACH)
/login → POST /api/auth/login { email, password }
→ 200 { accessToken, user } → localStorage → /inbox
→ 401 → mensaje error en form
| Campo | Validación cliente | API |
|---|---|---|
| required, email | @IsEmail() | |
| password | required, min 6 | @MinLength(6) |
Éxito: token guardado; user role=COACH, nombre Nora Beltrán.
Errores:
| Caso | Comportamiento |
|---|---|
| Credenciales inválidas | 401 + mensaje |
| Red caída | Error de red en UI |
| Token caducado en inbox | 401 en GET → re-login |
F5 — Inbox + stats (COACH)
/inbox (token en cliente)
→ GET /api/requests
→ GET /api/requests/stats/summary
→ Render cards + métricas
| Caso | Comportamiento |
|---|---|
| Lista con items | Cards: code, nombre, classType, status, preferencias |
| Lista vacía | Empty state (sin CTA público desde inbox) |
| Fallo red / 401 | Error + reintentar / re-login |
| Stats | total, open (NEW+CONTACTED), byStatus |
F6 — Detalle y cambio de estado (COACH)
/inbox/:id
→ GET /api/requests/:id
→ UI: datos contacto + preferencias + notas
→ PATCH /api/requests/:id/status { status }
→ 200 ClassRequest actualizado
Transiciones permitidas (modelo v1)
Cualquier status del enum puede asignarse vía PATCH (máquina simple L1):
| Desde | Hacia típico | Intención |
|---|---|---|
| NEW | CONTACTED | Coach inició contacto |
| CONTACTED | CONFIRMED | Plaza cerrada |
| CONTACTED | CANCELLED | No contesta / sin hueco |
| NEW | CANCELLED | Spam / error |
| CONFIRMED | CANCELLED | Baja posterior |
| * | * | Corrección operativa |
Éxito: badge de estado actualizado; lista refleja al volver.
Errores: 404 id inexistente; 401 sin token; 400 status inválido.
F7 — Logout (COACH)
Click "Salir" → limpia localStorage (token + user) → /login
Matriz de errores global
| Código | Cuándo | UI |
|---|---|---|
| 400 | DTO inválido | Mensaje campo / genérico |
| 401 | Sin/mal token | Re-login |
| 404 | id no existe | Mensaje detalle |
| 5xx / network | API caída | Empty error + retry |
Flujos fuera de alcance v1
- Registro de socio
- Recuperación de password
- Notificación email automática al coach
- Filtros multi-criterio en inbox
- Asignación multi-coach
05-data-model.md
Abrir documento05 — Modelo de datos — VOLTA
1. Visión general
Dominio mínimo de club L1:
| Entidad | Propósito |
|---|---|
| User | Identidad coach (rol COACH) |
| ClassRequest | Solicitud de plaza con preferencias y estado |
Base: PostgreSQL (Neon) · ORM: Prisma · IDs: cuid().
2. Enums
Role
| Valor | Descripción |
|---|---|
COACH | Operador del inbox; único rol autenticado v1 |
RequestStatus
| Valor | Descripción |
|---|---|
NEW | Recién creada por el form público |
CONTACTED | Coach ha iniciado contacto |
CONFIRMED | Plaza confirmada |
CANCELLED | Anulada |
ClassType
| Valor | Descripción |
|---|---|
HIIT | Entrenamiento alta intensidad |
YOGA | Yoga / movilidad |
BASKET | Baloncesto / cancha |
KIDS | Clase infantil |
OPEN | Cancha abierta / libre |
3. Diagrama ER (texto)
User
id, email, passwordHash, name, role(COACH)
createdAt, updatedAt
ClassRequest
id, code (unique)
fullName, email, phone?
classType, preferredDay, preferredSlot, notes
status (default NEW)
createdAt, updatedAt
No hay FK entre ClassRequest y User en v1: el form es anónimo (sin cuenta). El coach opera sobre el conjunto global de solicitudes.
4. Tablas / modelos Prisma
User
| Campo | Tipo | Constraints |
|---|---|---|
| id | String | PK, cuid |
| String | unique | |
| passwordHash | String | bcrypt |
| name | String | |
| role | Role | default COACH |
| createdAt | DateTime | default now |
| updatedAt | DateTime | updatedAt |
ClassRequest
| Campo | Tipo | Constraints |
|---|---|---|
| id | String | PK, cuid |
| code | String | unique, formato VO-MMDD-XXX |
| fullName | String | |
| String | ||
| phone | String? | opcional |
| classType | ClassType | enum |
| preferredDay | String | fecha preferida (ISO date string) |
| preferredSlot | String | franja / hora preferida |
| notes | String | default "" |
| status | RequestStatus | default NEW |
| createdAt / updatedAt | DateTime |
5. Reglas de integridad y negocio
| Regla | Implementación |
|---|---|
| Create público | POST /api/requests sin guard |
| List/detail/status | JwtAuthGuard → 401 sin token |
| Código único | code unique; generación VO-MMDD- + random 100–999 |
| Status default | NEW al crear |
| Password | Nunca en claro; solo passwordHash |
| Notas | Coalesce a "" si omitidas |
| Orden listado | createdAt desc |
6. Contratos API (resumen)
POST /api/requests (público)
Body
| Campo | Tipo | Req |
|---|---|---|
| fullName | string | sí |
| string | sí | |
| phone | string | no |
| classType | ClassType | sí |
| preferredDay | string | sí |
| preferredSlot | string | sí |
| notes | string | no |
Response 201: ClassRequest completo.
POST /api/auth/login
Body: { email, password }
Response 200: { accessToken, user: { id, email, name, role } }
GET /api/requests (JWT)
Array ClassRequest ordenado por createdAt desc.
GET /api/requests/stats/summary (JWT)
{
"total": 5,
"open": 3,
"byStatus": {
"NEW": 2,
"CONTACTED": 1,
"CONFIRMED": 1,
"CANCELLED": 1
}
}
open = NEW + CONTACTED.
GET /api/requests/:id (JWT)
ClassRequest o 404.
PATCH /api/requests/:id/status (JWT)
Body: { status: RequestStatus }
Response: ClassRequest actualizado.
7. Seed de referencia (2026-08-08)
| Entidad | Datos |
|---|---|
| COACH | Nora Beltrán · coach@volta.club · password123 |
| VO-0808-01 | Marc Solé · HIIT · NEW · 19:00 |
| VO-0808-02 | Laia Puig · YOGA · CONTACTED · 10:00 |
| VO-0808-03 | Eric Font · BASKET · NEW · 18:00 |
| VO-0808-04 | Sofía Rami · KIDS · CONFIRMED · 17:00 |
| VO-0808-05 | Pol Serra · OPEN · CANCELLED · 20:00 |
El sufijo de fecha del código de seed es representativo del día del caso; la generación runtime usa la fecha del servidor.
8. Evolución posible (no implementada)
| Cambio | Nivel |
|---|---|
| FK coachId en ClassRequest (asignación) | L2 |
| Tabla Class / Schedule con aforo | L2–L3 |
| User MEMBER con historial | L2 |
| Soft delete / auditoría | L2 |
06-tech-stack.md
Abrir documento06 — Stack tecnológico — VOLTA
1. Visión
| Capa | Tecnología | Notas |
|---|---|---|
| Frontend | Angular (standalone components) | Puerto 4200 |
| Estilos | Tailwind CSS | Tokens chalk/ink/lime |
| Backend | NestJS (TypeScript) | Puerto 3008, prefijo /api |
| ORM | Prisma | schema + migrate + seed |
| DB | Neon PostgreSQL serverless | project delicate-mountain-11765167 |
| Auth | JWT (passport strategy) | Bearer header |
| Diseño | Paper | file 01KZG2VRQFF2QF0PRDB10D4AG7 |
| Repo | /Users/cristian/orca/volta-app/ | GitHub Criscode2022/volta-app |
Stack fijo del cron: no se sustituye por React/Next/Firebase salvo excepción documentada.
2. Estructura monorepo app
volta-app/
├── apps/
│ ├── api/ # NestJS + Prisma
│ │ ├── prisma/
│ │ │ ├── schema.prisma
│ │ │ ├── seed.ts
│ │ │ └── migrations/
│ │ └── src/
│ │ ├── auth/
│ │ ├── requests/
│ │ ├── prisma/
│ │ └── main.ts
│ └── web/ # Angular + Tailwind
│ └── src/app/
│ ├── pages/
│ ├── core/api.service.ts
│ └── app.routes.ts
├── package.json # scripts api / web
└── README.md
Regla D-P1-03: apps/api y apps/web independientes (npm install --prefix), sin workspaces npm que rompan Angular CLI.
3. Backend
| Pieza | Detalle |
|---|---|
| Framework | NestJS modules: Auth, Requests, Prisma |
| Validación | class-validator DTOs |
| Hash | bcrypt passwords |
| CORS | Habilitado para dev web :4200 |
| Puerto | 3008 (env PORT opcional) |
| Prefijo global | /api |
Módulos
| Módulo | Responsabilidad |
|---|---|
AuthModule | login, JWT sign, strategy |
RequestsModule | CRUD-lite solicitudes |
PrismaModule | PrismaService global |
4. Frontend
| Pieza | Detalle |
|---|---|
| Angular | Standalone pages, RouterLink, HttpClient |
| Estado auth | localStorage keys volta_token, volta_user |
| API base | http://localhost:3008/api en ApiService |
| Fuentes | Syne + Work Sans (link Google Fonts / index) |
| Media | assets/hero.jpg |
Rutas web
| Path | Componente |
|---|---|
/ | HomePage |
/apuntarme | JoinPage |
/ok | SuccessPage |
/login | LoginPage |
/inbox | InboxPage |
/inbox/:id | RequestDetailPage |
5. Base de datos
| Campo | Valor |
|---|---|
| Provider | PostgreSQL |
| Hosting | Neon |
| Project | delicate-mountain-11765167 |
| Migraciones | Prisma migrate (init) |
| Seed | prisma/seed.ts → 1 coach + 5 requests |
6. Seguridad técnica (resumen)
| Control | Implementación |
|---|---|
| Password | bcrypt hash |
| API coach | JwtAuthGuard en GET/PATCH |
| Form público | solo POST create |
| Secret | JWT_SECRET en env API |
| PII | no exponer list en endpoints públicos |
Detalle en 11-privacy-security.md.
7. Scripts típicos
cd /Users/cristian/orca/volta-app
npm install --prefix apps/api
npm install --prefix apps/web
# apps/api/.env → DATABASE_URL + JWT_SECRET
npm --prefix apps/api run prisma:migrate
npm --prefix apps/api run prisma:seed
npm run api # :3008
npm run web # :4200
8. Decisiones técnicas
| Decisión | Razón |
|---|---|
| Puerto API 3008 | No colisionar con SURCO 3007 y anteriores |
| preferredDay/Slot como String | L1 simple; evita timezone complexity |
| Sin FK coach–request | Form anónimo; asignación multi-coach = L2 |
| Soft auth en Angular | API es autoridad; guards formales = L1+ |
| Stats endpoint propio | Evita recalcular en cliente |
9. Dependencias clave (orientativo)
| Capa | Paquetes |
|---|---|
| API | @nestjs/*, @prisma/client, bcrypt, passport-jwt, class-validator |
| Web | @angular/*, tailwindcss, RxJS |
10. Despliegue (recomendado, no obligatorio del día)
| Servicio | Opción |
|---|---|
| Web | Vercel / Netlify / static host |
| API | Railway / Fly / Render |
| DB | Neon (ya provisionada) |
Variables: DATABASE_URL, JWT_SECRET, PORT, y en web la URL pública de API.
07-creative-direction.md
Abrir documento07 — Dirección creativa — VOLTA
1. Concepto de marca
| Campo | Valor |
|---|---|
| Nombre | VOLTA |
| Eslogan | ”Tu plaza en la cancha.” |
| Territorio | Club de barrio, energía real, sin greña de gym chain |
| Promesa | Un hueco en el grupo — claro, cercano, sin fricción digital innecesaria |
| Tono | Directo, deportivo, vecinal; cero jerga corporativa “wellness SaaS” |
Metáfora
Volta evoca la vuelta a la cancha, el regreso al grupo, el ciclo del entrenamiento semanal. Visualmente: tiza (chalk) de pizarra de vestuario × tinta negra de dorsal × lima neón de línea de campo.
2. Personalidad (arquetipos)
| Eje | Posición |
|---|---|
| Formal ↔ Informal | Informal profesional |
| Suave ↔ Enérgico | Enérgico contenido |
| Lujo ↔ Barrio | Barrio con craft |
| Genérico fitness ↔ Local | Local, Valencia en copy |
3. Sistema visual
Color
| Rol | Hex | Emoción |
|---|---|---|
| Chalk bg | #F7F7F2 | Pizarra limpia, aire |
| Ink | #0B0B0B | Dorsal, decisión, fuerza |
| Lime | #C6F23A | Señal de campo, energía |
| Muted | #5C5C58 | Texto secundario |
| Border | #E2E2DC | Separación suave |
| Surface | #FFFFFF | Cards, legibilidad |
Regla: el lime es acento, no relleno masivo. CTAs principales pueden ser ink (texto lime) o lime (texto ink) según jerarquía.
Tipografía
| Uso | Familia | Carácter |
|---|---|---|
| Display | Syne | Geométrica, deportiva, wordmark |
| UI / body | Work Sans | Legible, humana, forms |
Forma
- Radios grandes (
rounded-2xl, pillsrounded-full) → amable sin “bubble tea app”. - Bordes 1px
#E2E2DC→ estructura de vestuario limpio. - Hero con foto real de cancha/club — no ilustración stock abstracta.
4. Moodboard verbal
| Sí | No |
|---|---|
| Cancha de barrio, sudor real, luz de polideportivo | Luxury spa fitness, mármol rosa |
| Lime como spray de línea | Gradientes púrpura genéricos |
| Syne bold en titulares | Inter/Roboto por defecto sin intención |
| Microcopy “plaza”, “cancha”, “coach” | “Optimiza tu wellness journey” |
| Dark ink sections para contraste | Todo gris flat SaaS |
5. Fotografía y media
| Asset | Uso |
|---|---|
assets/hero.jpg | Home hero, posible cover Paper |
| Alt text | Descriptivo: “Cancha de un club deportivo de barrio” |
[DECISIÓN DE DISEÑO]: media fotorrealista obligatoria (D-P0-05); no placeholders grises.
6. Voz en UI (preview; detalle en doc 09)
| Contexto | Ejemplo |
|---|---|
| Hero | “Tu plaza en la cancha.” |
| CTA | “Quiero una plaza” / “Apuntarme” |
| Success | “Solicitud enviada” + código VO- |
| Coach empty | “No hay solicitudes todavía.” |
| Error | “No se pudo cargar el inbox. Reintenta.” |
7. Diferenciación en la serie ALS-2
| Proyecto | Paleta / tono | VOLTA se diferencia por… |
|---|---|---|
| SURCO | Bone/leaf agro | Energía urbana lime, no rural |
| CORREA | Marketplace pet | Club único, no matching |
| TROCHA | Ops logística | Emoción de cancha, no flota |
| MERIDIANA | Clínica | Informal deportivo, no sanitario |
8. Criterios de aceptación creativa
- Un scroll de home se reconoce como club de barrio, no como template Tailwind.
- Syne aparece en logo y H1; Work Sans en body/forms.
- Lime presente en CTAs o highlights sin saturar fondos.
- Hero real; sin lorem en artboards Paper ni app.
- Panel coach mantiene mismos tokens (no “admin theme” gris aparte).
08-design-system.md
Abrir documento08 — Design system — VOLTA
1. Fundamentos
| Capa | Valor |
|---|---|
| Nombre DS | VOLTA UI (L1 vertical slice) |
| Principio | Energía de cancha + claridad operativa del inbox |
| Plataformas | Web responsive 360–1280+ |
| Implementación | Tailwind tokens + componentes de página (no lib publicada) |
2. Color tokens
Marca (fuente de verdad del caso)
| Token | Hex | Uso |
|---|---|---|
color.bg.chalk | #F7F7F2 | Background app/marketing |
color.surface | #FFFFFF | Cards, header |
color.ink | #0B0B0B | Texto fuerte, CTAs dark |
color.ink.muted | #5C5C58 | Secundario |
color.lime | #C6F23A | Acento, highlights, CTA lime |
color.lime.soft | #EAF8B8 | Badges soft, fondos suaves |
color.lime.strong | #A8D420 | Hover lime |
color.border | #E2E2DC | Bordes |
color.danger | aprox red-700 | Errores de form / red |
Mapeo Tailwind app
| Clase | Valor implementado |
|---|---|
bg-bg | #F7F7F2 |
bg-surface | #FFFFFF |
text-ink / ink-muted | #0B0B0B / #5C5C58 |
primary / primary-soft / primary-strong | #0B0B0B / #EFEFEA / #000000 |
lime / lime-soft / lime-strong | #C6F23A / #EAF8B8 / #A8D420 |
border-border | #E2E2DC |
3. Tipografía
| Token | Familia | Fallback |
|---|---|---|
font.display | Syne | system-ui, sans-serif |
font.sans | Work Sans | system-ui, sans-serif |
| Estilo | Spec |
|---|---|
| Display xl | Syne 36–60/800, leading ~1.05 |
| Title | Syne 28–32/700–800 |
| Body | Work Sans 16/400–500, leading relaxed |
| Label | Work Sans 11–12/700 uppercase o tracking wide |
| Button | Work Sans 14/700 |
4. Espaciado y radio
| Token | Valor |
|---|---|
| page padding x | 16–24px |
| section y | 40–56px |
| card padding | 16–24px |
| gap grid | 12–16px |
| radius.card | 16–20px (rounded-2xl) |
| radius.pill | 9999px (rounded-full) |
| header height | ~72px |
5. Componentes
5.1 Botones
| Variante | Estilo | Uso |
|---|---|---|
| Primary dark | bg ink, text lime, pill | Nav “Apuntarme” |
| Primary lime | bg lime, text ink, pill | Hero CTA principal |
| Secondary | border border, bg surface, pill | “Ver clases” |
| Ghost/text | text muted, hover ink | Enlaces nav, salir |
Estados: default · hover (strong) · disabled (opacidad) · focus visible ring.
5.2 Badges de estado
| Status | Label | Estilo sugerido |
|---|---|---|
| NEW | Nueva | lime soft / ink |
| CONTACTED | Contactada | primary soft / muted |
| CONFIRMED | Confirmada | lime o soft positivo |
| CANCELLED | Cancelada | muted / borde dashed opcional |
Regla a11y: no codificar solo con color; siempre texto del label.
5.3 Badges de ClassType
| Tipo | Label | Notas |
|---|---|---|
| HIIT | HIIT | tracking bold |
| YOGA | Yoga | |
| BASKET | Basket | |
| KIDS | Kids | |
| OPEN | Cancha abierta |
5.4 Cards de solicitud (inbox)
Estructura:
- Meta:
code · classType(xs bold, muted o lime) - Nombre completo (lg semibold)
- Día preferido · franja
- Email / teléfono
- Badge status (trailing)
5.5 Stats summary
| Métrica | Fuente |
|---|---|
| Total | stats.total |
| Abiertas | stats.open (NEW+CONTACTED) |
| Por estado | stats.byStatus.* |
Layout: grid 2–4 cards compactas sobre la lista.
5.6 Form fields
| Elemento | Spec |
|---|---|
| Label | Work Sans 12–14/600 |
| Input | border border, rounded-xl, bg surface, focus ring ink/lime |
| Select ClassType | mismos tokens |
| Error | text danger, bajo el campo |
| Submit | full-width en móvil, pill |
5.7 Header
| Zona | Contenido |
|---|---|
| Pública | Logo · nav · CTA Apuntarme |
| Coach | Logo · badge COACH · nombre · Salir |
6. Layout patterns
| Pattern | Uso |
|---|---|
| Marketing split | Home: copy + hero image 2 col |
| Dark band | Sección clases sobre ink |
| App shell simple | Inbox full-width max-w-6xl |
| Detail stack | Meta → contacto → preferencias → acciones |
7. Iconografía
L1: preferir tipografía y badges; iconos mínimos si se usan (stroke 1.5–2, ink). No librería obligatoria.
8. Motion
| Interacción | Spec |
|---|---|
| Hover CTA | color strong, 150ms |
| Page transitions | router default (sin lib motion) |
| Feedback submit | disabled + label “Enviando…” opcional |
9. Do / Don’t
| Do | Don’t |
|---|---|
| Lime como acento | Fondos enteros lime sin contraste |
| Syne solo display | Syne en párrafos largos |
| Datos seed reales en mockups | Lorem ipsum |
| Empty/error con copy | Pantallas en blanco |
09-content-guide.md
Abrir documento09 — Guía de contenido — VOLTA
1. Voz y tono
| Atributo | Descripción |
|---|---|
| Directo | Frases cortas; verbo en imperativo en CTAs |
| Vecinal | “club de barrio”, “cancha”, “plaza” — no “ecosistema fitness” |
| Respetuoso | Trato de tú; sin paternalismo “tú puedes con todo” |
| Operativo en coach | Labels de estado claros; cero motivacional vacío |
Registro
| Contexto | Registro |
|---|---|
| Marketing home | Enérgico, cercano |
| Formulario | Neutro, claro, labels explícitos |
| Success | Confirmatorio, tranquilizador |
| Panel coach | Técnico-ligero, denso en datos |
| Errores | Honestos, accionables |
2. Glosario de producto (copy)
| Usar | Evitar |
|---|---|
| Plaza | Slot genérico sin contexto |
| Solicitud | Ticket / lead (salvo docs técnicas) |
| Coach | Admin / backoffice |
| Cancha abierta | OPEN crudo en UI visitante (sí en API) |
| Apuntarme | Sign up / registrarse (implica cuenta) |
| Contactada | “En progreso” ambiguo |
3. Microcopy por pantalla
Home
| Elemento | Copy |
|---|---|
| Eyebrow | CLUB DE BARRIO · VALENCIA |
| H1 | Tu plaza en la cancha. |
| Lead | Entrenamientos en grupo, cancha abierta y monitores del barrio. Reserva tu hueco sin cadenas de WhatsApp ni listas en el mostrador. |
| CTA primary | Quiero una plaza |
| CTA secondary | Ver clases |
| Stat 1 | CLASES · 5 tipos |
| Stat 2 | RESPUESTA · < 24 h [HIPÓTESIS de promesa de servicio, no KPI medido] |
| Stat 3 | PANEL · Coach JWT |
| Clases intro | Hipótesis de oferta del club (contenido de producto, no catálogo real verificado). |
| Footer demo | Credenciales coach demo si se documentan |
Join (/apuntarme)
| Elemento | Copy |
|---|---|
| Título | Pide tu plaza |
| Sub | Te contactamos para confirmar el hueco. |
| fullName | Nombre completo |
| phone | Teléfono (opcional) |
| classType | Tipo de clase |
| preferredDay | Día preferido |
| preferredSlot | Franja preferida |
| notes | Notas (opcional) |
| Submit | Enviar solicitud |
| Error genérico | No se pudo enviar. Revisa los datos e inténtalo. |
Success (/ok)
| Elemento | Copy |
|---|---|
| Título | Solicitud enviada |
| Body | Hemos recibido tu petición. Guarda tu código de referencia. |
| Code label | Tu código |
| Next | El coach del club te contactará para confirmar. |
| CTA | Volver al inicio |
Login
| Elemento | Copy |
|---|---|
| Título | Panel coach |
| Sub | Entra para gestionar solicitudes de plaza. |
| password | Contraseña |
| Submit | Entrar |
| Error | No se pudo entrar. Revisa email y contraseña. |
Inbox
| Elemento | Copy |
|---|---|
| Título | Solicitudes |
| Stats labels | Total · Abiertas · Nueva · Contactada · Confirmada · Cancelada |
| Empty | No hay solicitudes todavía. |
| Error | No se pudo cargar el inbox. Reintenta. |
| Salir | Salir |
Detail
| Elemento | Copy |
|---|---|
| Volver | ← Inbox |
| Acciones | Marcar contactada · Confirmar plaza · Cancelar |
| Notas vacías | Sin notas |
4. Labels de enums (UI)
| API | Label ES |
|---|---|
| NEW | Nueva |
| CONTACTED | Contactada |
| CONFIRMED | Confirmada |
| CANCELLED | Cancelada |
| HIIT | HIIT |
| YOGA | Yoga |
| BASKET | Basket |
| KIDS | Kids |
| OPEN | Cancha abierta |
5. Principios de redacción
- Una idea por frase en marketing.
- Verbos de acción en botones (no “OK” / “Submit”).
- Errores con siguiente paso (“Reintenta”, “Revisa…”).
- No inventar stats de mercado; si hay promesa de servicio, etiquetarla como hipótesis de producto.
- Español peninsular neutro (es-ES); sin anglicismos innecesarios salvo HIIT, JWT en footer técnico.
6. Contenido de demo / seed (nombres)
| Código | Nombre | Clase | Estado |
|---|---|---|---|
| VO-0808-01 | Marc Solé | HIIT | Nueva |
| VO-0808-02 | Laia Puig | Yoga | Contactada |
| VO-0808-03 | Eric Font | Basket | Nueva |
| VO-0808-04 | Sofía Rami | Kids | Confirmada |
| VO-0808-05 | Pol Serra | Cancha abierta | Cancelada |
Coach: Nora Beltrán · coach@volta.club
7. Accesibilidad de copy
- Badges con texto, no solo color.
- Alt de hero descriptivo.
- Placeholders no sustituyen labels.
- Errores asociados al campo cuando sea posible.
10-accessibility.md
Abrir documento10 — Accesibilidad — VOLTA
1. Objetivo
Orientar la UI a WCAG 2.2 AA en lo razonable para un vertical slice L1.
No se afirma auditoría formal certificada; se listan requisitos y checks manuales.
2. Principios aplicados
| Principio | Aplicación VOLTA |
|---|---|
| Perceptible | Contraste ink/chalk; lime solo con texto ink o como acento |
| Operable | Targets ≥44px en CTAs y acciones de estado; teclado en forms |
| Comprensible | Labels ES; errores claros; estados con texto |
| Robusto | HTML semántico en templates Angular; focus visible |
3. Color y contraste
| Par | Uso | Nota |
|---|---|---|
Ink #0B0B0B sobre chalk #F7F7F2 | Body | Alto contraste |
| Ink sobre white | Cards | Alto contraste |
Lime #C6F23A + ink text | CTA lime | Preferir texto ink sobre lime |
| Lime text sobre ink bg | Nav CTA / dark band | Verificar en UI real |
Muted #5C5C58 sobre chalk | Secundario | Evitar muted sobre muted |
Prohibido: transmitir estado solo con color (badges llevan label).
4. Tipografía y legibilidad
| Regla | Spec |
|---|---|
| Body mínimo | 16px |
| Line-height body | ≥ 1.5 relajado |
| Display | Syne; no párrafos largos en display |
| Zoom | Layout usable al 200% (responsive) |
5. Teclado y foco
| Flujo | Requisito |
|---|---|
| Join form | Tab order lógico; submit con Enter |
| Login | Igual |
| Inbox cards | Click + teclado si son links/botones |
| Detail actions | Botones focusables, no solo divs |
| Focus ring | Visible (ring ink o lime) |
6. Formularios
| Control | a11y |
|---|---|
| Labels | Visible, asociado al control |
| Required | Indicado en UI + validación |
| Errors | Mensaje textual bajo campo o form |
| Phone optional | Marcado “(opcional)” |
| Select ClassType | Opciones con labels legibles |
7. Imágenes y media
| Asset | Regla |
|---|---|
| hero.jpg | alt descriptivo no vacío |
| Decorative | alt vacío solo si puramente decorativo |
8. Auth y áreas coach
| Tema | Nota |
|---|---|
| Logout | Control con nombre accesible “Salir” |
| Errores 401 | Mensaje no solo cambio de color |
| Empty/error | Heading o texto de estado legible por SR |
9. Checklist de verificación manual (QA)
| # | Check | OK? |
|---|---|---|
| A1 | Contraste H1 y body en home | |
| A2 | CTA lime con texto legible | |
| A3 | Form join usable solo teclado | |
| A4 | Badges status con texto | |
| A5 | Alt hero presente | |
| A6 | Error login anunciable | |
| A7 | Targets touch ≥44px en móvil | |
| A8 | No hay texto en imagen como única info |
10. Deuda a11y aceptada L1
| Ítem | Clasificación |
|---|---|
| Auditoría axe automatizada en CI | L1+ |
| Live regions formales ARIA en todos los async | L1+ |
| Skip link | Nice-to-have |
| i18n multi-idioma | Fuera |
11. Criterio de aceptación
La demo es usable con teclado en form y login; contraste principal cumple intención AA; estados no dependen solo del color.
11-privacy-security.md
Abrir documento11 — Privacidad y seguridad — VOLTA
1. Contexto
VOLTA trata datos de contacto y preferencias de clase de visitantes (PII ligera) y credenciales del coach.
Alcance L1 demo: no es un DPIA formal; documenta decisiones de diseño y controles implementados.
2. Datos tratados
| Dato | Entidad | Sensibilidad | Base demo |
|---|---|---|---|
| Nombre completo | ClassRequest | PII | Consentimiento implícito al enviar form [DECISIÓN demo] |
| ClassRequest / User | PII | Igual | |
| Teléfono | ClassRequest | PII | Opcional |
| Preferencias clase/día/franja | ClassRequest | Baja | Necesarias al servicio |
| Notas | ClassRequest | Variable | Texto libre del visitante |
| Password | User | Secreto | Solo hash bcrypt |
| JWT | Cliente | Sesión | localStorage (demo) |
3. Superficies de exposición
| Superficie | Riesgo | Control v1 |
|---|---|---|
| POST /api/requests | Spam / PII entrada | Validación DTO; rate-limit futuro |
| GET /api/requests | Filtración lista PII | JwtAuthGuard obligatorio |
| GET /api/requests/:id | PII individual | JWT |
| PATCH status | Abuso de estado | JWT |
| Login | Fuerza bruta | bcrypt; rate-limit futuro |
| localStorage token | XSS robo sesión | App trusted demo; CSP futuro |
4. Controles de seguridad implementados
| Control | Estado |
|---|---|
| Passwords hasheados bcrypt | Sí |
JWT firmado con JWT_SECRET | Sí |
| Rutas coach protegidas | Sí |
| Create público solo POST | Sí |
| Password en respuestas | No (nunca) |
| HTTPS en producción | Recomendado (Neon + host) |
| CORS restringido prod | Configurar al desplegar |
5. Autorización
| Actor | Puede |
|---|---|
| Anónimo | POST request; ver páginas públicas |
| COACH autenticado | Listar, ver detalle, cambiar status |
| Sin rol MEMBER | No existe en v1 |
6. Privacidad (RGPD — orientación)
| Principio | Aplicación v1 |
|---|---|
| Minimización | Campos justos para contactar y preferir clase |
| Limitación finalidad | Gestión de plazas del club |
| Conservación | Demo seed; política de borrado no automatizada |
| Derechos ARCO/RGPD | Proceso manual fuera de app |
| Transparencia | Mejorable: enlace política L1+ |
| Consentimiento kids | Notas “hija 8 años” en seed = ejemplo; en prod se requeriría base legal parental [HIPÓTESIS legal] |
No se afirma cumplimiento RGPD certificado. Es un mapa de riesgos para el case.
7. Amenazas y mitigaciones
| Amenaza | Impacto | Mitigación |
|---|---|---|
| Enumeración de inbox sin auth | Alto | Guard JWT |
| Spam de solicitudes | Medio | Validación; captcha L1+ |
| Token en localStorage | Medio | Demo; HttpOnly cookie L2 |
| Secret débil JWT | Alto | Env no commitear |
| Notas con datos sensibles | Medio | Copy: evitar datos médicos |
| Credenciales demo públicas | Bajo (demo) | Documentadas a propósito |
8. Logging y secretos
| Regla |
|---|
| No loguear passwords ni tokens completos |
DATABASE_URL y JWT_SECRET solo en .env |
| Seed password solo en docs de demo |
9. Checklist de seguridad demo
| # | Check |
|---|---|
| S1 | GET /api/requests sin header → 401 |
| S2 | PATCH sin header → 401 |
| S3 | Login password incorrecto → 401 |
| S4 | Password no en JSON de user |
| S5 | .env no en git |
10. Evolución recomendada (no deuda L1)
- Rate limiting + captcha en POST público
- Consent checkbox + política de privacidad
- Rotación JWT / refresh
- Soft-delete y retención configurable
- Audit log de cambios de status
12-analytics.md
Abrir documento12 — Analytics y métricas — VOLTA
1. Objetivo
Definir el modelo de medición del producto.
En v1 L1 la instrumentación puede ser mínima o nula en código; las métricas guían producto y roadmap.
No se reportan dashboards con números inventados como si fueran producción.
2. North Star
| Métrica | Definición | Por qué |
|---|---|---|
| Plazas confirmadas / semana | Count ClassRequest con status CONFIRMED creadas o confirmadas en la ventana | Mide cierre real del job del club |
3. Árbol de métricas
| Nivel | Métrica | Definición |
|---|---|---|
| Input | Visitas home | Page view / |
| Activación visitante | Solicitudes enviadas | POST /api/requests 2xx |
| Calidad captura | % forms con phone | phone non-null / total |
| Ops | Tiempo NEW → CONTACTED | Mediana hours |
| Ops | Tiempo NEW → CONFIRMED | Mediana hours |
| Ops | % open (NEW+CONTACTED) | open / total |
| Salud | Error rate API | 5xx / total |
| Coach | Logins / día | POST login 200 |
4. Eventos propuestos (schema)
| Evento | Props | Trigger |
|---|---|---|
home_viewed | — | Enter / |
join_started | — | Enter /apuntarme |
join_submitted | classType | Submit form |
join_succeeded | code, classType | 201 |
join_failed | reason | 4xx/5xx/network |
success_viewed | code | /ok |
coach_login_succeeded | — | 200 login |
coach_login_failed | — | 401 |
inbox_viewed | total, open | load inbox |
request_opened | id, status | detail |
status_changed | id, from, to | PATCH 200 |
5. Funnels
Funnel visitante
home_viewed → join_started → join_submitted → join_succeeded → (offline) contact → CONFIRMED
| Paso | Fricción esperada [HIPÓTESIS] |
|---|---|
| Home → Join | CTA claro reduce drop |
| Join → Success | Validación y red |
| Success → CONFIRMED | Ops del coach (fuera de web) |
Funnel coach
login → inbox_viewed → request_opened → status_changed(CONTACTED|CONFIRMED)
6. Segmentos
| Segmento | Cómo |
|---|---|
| Por ClassType | prop en eventos create/status |
| Por status | byStatus snapshot |
| Mobile vs desktop | UA / viewport (futuro) |
7. Implementación v1 vs futura
| Pieza | v1 L1 | Futuro |
|---|---|---|
| Logs API Nest | Opcional console | Structured logs |
| Product analytics | No obligatorio | Plausible / PostHog |
| Stats in-app | GET summary | + series temporales |
| A/B CTA copy | No | L2 |
8. KPIs de éxito del case (demo)
| KPI demo | Criterio |
|---|---|
| Seed visible | ≥5 requests en inbox tras seed |
| Create E2E | 1 request nueva aparece en list |
| Status E2E | PATCH refleja badge |
| Auth | Sin token no hay list |
9. Ética de medición
- No trackear notas libres con PII hacia terceros sin base legal.
- No inventar “conversión 37%” en el portfolio.
- Separar métrica modelo vs dato medido.
13-qa-test-plan.md
Abrir documento13 — Plan de QA y pruebas — VOLTA
1. Alcance
Validar el vertical slice L1: form público, success, login coach, inbox, detalle, estados, empty/error, seed Neon.
2. Entorno
| Variable | Valor |
|---|---|
| API | http://localhost:3008 |
| Web | http://localhost:4200 |
| DB | Neon delicate-mountain-11765167 |
| Coach | coach@volta.club / password123 |
3. Smoke tests (obligatorios)
| ID | Caso | Pasos | Esperado |
|---|---|---|---|
| S1 | Seed | prisma:seed | Log VOLTA seed OK |
| S2 | Login OK | POST /api/auth/login | 200 + accessToken |
| S3 | Login KO | password mal | 401 |
| S4 | Create public | POST /api/requests body válido | 201 + code VO-… + status NEW |
| S5 | List sin token | GET /api/requests | 401 |
| S6 | List con token | Authorization Bearer | 200 array ≥1 |
| S7 | Stats | GET /api/requests/stats/summary | total/open/byStatus |
| S8 | Detail | GET /api/requests/:id | 200 |
| S9 | Patch status | PATCH { "status": "CONTACTED" } | 200 status actualizado |
| S10 | Web home | abrir / | hero + CTA |
| S11 | Web join E2E | form → success | código visible |
| S12 | Web inbox | login → /inbox | cards seed |
4. Casos funcionales ampliados
Público
| ID | Caso | Esperado |
|---|---|---|
| P1 | Email inválido en join | 400 / error UI |
| P2 | classType fuera de enum | 400 |
| P3 | notes omitidas | notes "" |
| P4 | phone omitido | null/ausente OK |
Coach
| ID | Caso | Esperado |
|---|---|---|
| C1 | Token basura | 401 en list |
| C2 | id inexistente | 404 |
| C3 | status inválido | 400 |
| C4 | Transición NEW→CONFIRMED | 200 |
| C5 | Logout limpia sesión | list falla o redirect login |
UI estados
| ID | Caso | Esperado |
|---|---|---|
| U1 | Inbox vacío (DB clean sin seed) | empty copy |
| U2 | API parada | error + reintentar |
| U3 | Responsive 390px join | usables CTAs |
5. Regresión visual (manual)
| Pantalla | Check |
|---|---|
| Home | Syne H1, lime CTA, hero no roto |
| Join | labels, select tipos |
| Success | código monospaced o bold |
| Login | split/form legible |
| Inbox | badges status + stats |
| Detail | acciones de estado |
6. Seguridad smoke
Ver 11-privacy-security.md checks S1–S5.
7. Accesibilidad smoke
Ver 10-accessibility.md A1–A8.
8. Criterios de salida (release demo)
- S1–S12 OK
- Sin 500 en flujos felices
- Docs de case enlazadas
- Paper referenciado
9. Automatización futura
| Capa | Tool | Prioridad |
|---|---|---|
| API e2e | supertest / Playwright API | P1 L1+ |
| UI e2e | Playwright | P1 L1+ |
| a11y | axe | P2 |
| CI | GitHub Actions | P2 |
10. Datos de prueba recomendados
Además del seed:
| Nombre | Clase | Notas |
|---|---|---|
| Test User | OPEN | “prueba QA” |
| Ana Kids | KIDS | teléfono relleno |
14-dev-handoff.md
Abrir documento14 — Handoff de desarrollo — VOLTA
1. Fuentes de verdad
| Artefacto | Ubicación |
|---|---|
| Case docs | /Users/cristian/orca/ux-projects/2026-08-08-volta/docs/ |
| Paper | https://app.paper.design/file/01KZG2VRQFF2QF0PRDB10D4AG7 |
| App | /Users/cristian/orca/volta-app/ |
| Schema | apps/api/prisma/schema.prisma |
| Seed | apps/api/prisma/seed.ts |
| Tokens | apps/web/tailwind.config.js |
| Rutas web | apps/web/src/app/app.routes.ts |
| API client | apps/web/src/app/core/api.service.ts |
2. Setup local (checklist)
- Node LTS instalado.
- Clonar/usar
volta-app. - Copiar
apps/api/.env.example→.envconDATABASE_URL(Neon) yJWT_SECRET. npm install --prefix apps/api && npm install --prefix apps/web.- Migrar y seed.
npm run api(:3008) ynpm run web(:4200).- Smoke S2, S4, S6, S11, S12 (doc 13).
3. Contratos que no romper
| Contrato | Detalle |
|---|---|
| Prefijo API | /api |
| Login body | { email, password } |
| Login response | { accessToken, user } |
| Create request fields | fullName, email, phone?, classType, preferredDay, preferredSlot, notes? |
| Status patch | { status: RequestStatus } |
| Stats shape | { total, open, byStatus } |
| Token storage keys | volta_token, volta_user |
Cambios de contrato → actualizar docs 04, 05, 20 y Paper si afecta UI.
4. Mapa pantalla → API → modelo
| Pantalla | Métodos | Modelo |
|---|---|---|
| Join | POST requests | ClassRequest |
| Success | — (resultado create) | code |
| Login | POST auth/login | User |
| Inbox | GET requests, GET stats | ClassRequest[] |
| Detail | GET :id, PATCH status | ClassRequest |
5. Tokens UI a respetar
| Token | Hex |
|---|---|
| bg | #F7F7F2 |
| ink | #0B0B0B |
| lime | #C6F23A |
| muted | #5C5C58 |
| border | #E2E2DC |
| fonts | Syne + Work Sans |
No sustituir por tema default de Angular Material sin brief de diseño.
6. Convenciones de código
| Área | Convención |
|---|---|
| Angular | Standalone components por página |
| Nest | Module por dominio (auth, requests) |
| Prisma | Enums en schema; no strings sueltos de status |
| IDs | cuid |
| Códigos | VO-MMDD-XXX |
7. Definition of Done (feature)
- API + validación DTO
- UI con tokens y microcopy ES
- Empty/error si aplica lista
- Doc actualizada si cambia dominio
- Smoke manual del flujo
- Sin secretos en git
8. Ambientes
| Env | API | Web | DB |
|---|---|---|---|
| Local | :3008 | :4200 | Neon dev branch |
| Prod (futuro) | host API | host web | Neon main |
9. Contacto de dominio (roles ficticios demo)
| Rol | Persona |
|---|---|
| Product/UX case | Serie ALS-2 daily |
| Coach demo | Nora Beltrán |
10. Riesgos de implementación
| Riesgo | Mitigación |
|---|---|
| CORS en prod | Whitelist origen web |
| API URL hardcode | Environment Angular L1+ |
Orden rutas Nest stats vs :id | stats/summary declarado antes de :id [COMPROBADO en controller] |
15-roadmap.md
Abrir documento15 — Roadmap — VOLTA
1. Principio
El L1 del día está cerrado. Este roadmap no es deuda del alcance 2026-08-08; son opciones de evolución con subida de complejidad o polish.
2. Hecho (L1 — 2026-08-08)
| Área | Entrega |
|---|---|
| Producto | Web club + solicitud + inbox coach |
| Dominio | User COACH + ClassRequest + enums |
| Auth | JWT login |
| API | POST public + GET/PATCH JWT + stats |
| Web | Home, join, success, login, inbox, detail |
| Data | Neon + Prisma + seed |
| Diseño | Paper §1–§5 + tokens chalk/ink/lime |
| Docs | Suite 00–20 + README + executive |
3. L1+ (misma complejidad, mejoras)
| ID | Ítem | Valor |
|---|---|---|
| L1+01 | canActivate guards Angular en /inbox | UX auth |
| L1+02 | Filtros por status en inbox | Ops |
| L1+03 | Toast éxito create/status | Feedback |
| L1+04 | Captcha / rate limit POST | Anti-spam |
| L1+05 | Checkbox privacidad en form | RGPD |
| L1+06 | Playwright smoke S1–S12 | CI |
| L1+07 | Skeleton loading inbox | Polish |
| L1+08 | click-to-call / mailto en detail | Ops coach |
| L1+09 | Environment-based API URL | Deploy |
| L1+10 | Página 404 amigable | IA |
4. L2 (nuevo brief)
| ID | Ítem | Dependencia |
|---|---|---|
| L2-01 | Calendario semanal de clases | Schedule model |
| L2-02 | Aforo por franja | capacity field |
| L2-03 | Multi-coach + asignación | coachId FK |
| L2-04 | Email al coach al crear | provider email |
| L2-05 | Área “mi solicitud” por código | lookup público acotado |
| L2-06 | Notas internas coach | campo staffNotes |
| L2-07 | Export CSV semana | reporting |
5. L3+ (explícitamente mayor)
| ID | Ítem |
|---|---|
| L3-01 | Multi-sede / multi-tenant |
| L3-02 | Pagos y cuotas |
| L3-03 | App nativa / push |
| L3-04 | Marketplace de clubs |
| L3-05 | Wearables / planes IA |
6. No-roadmap (fuera de VOLTA)
| Idea | Razón |
|---|---|
| Agro / parcelas | SURCO |
| Flota GPS | TROCHA |
| Expedientes legales | FIRME |
| Matching pet services | CORREA |
7. Priorización sugerida si hay continuidad
- L1+01 guards + L1+06 e2e
- L1+02 filtros + L1+08 contact shortcuts
- L1+04 anti-spam si hay tráfico real
- Evaluar L2 calendario solo con uso coach real
8. Métricas que desbloquean L2
| Señal | Umbral ejemplo [HIPÓTESIS] |
|---|---|
| Solicitudes / semana | > 20 sostenidas |
| % NEW sin CONTACTED > 48 h | > 30% → priorizar ops tools |
| Coach pide aforo | Entrevistas / feedback real |
16-interaction-specs.md
Abrir documento16 — Especificaciones de interacción — VOLTA
1. Convenciones
| Token | Valor |
|---|---|
| Duración hover | ~150ms ease |
| Focus | ring 2px ink o lime |
| Disabled | opacity 0.5, cursor not-allowed |
| Touch min | 44×44 px |
2. Home
| Elemento | Interacción |
|---|---|
| Nav anchors | Smooth scroll opcional a #clases / #horarios |
| CTA “Quiero una plaza” | Navigate /apuntarme |
| CTA “Ver clases” | Scroll #clases |
| CTA “Apuntarme” header | Navigate /apuntarme |
| “Coach” | Navigate /login |
| Hero image | Estática; no lightbox v1 |
| Cards de clase | Informativas; CTA global a join |
Estados: solo estáticos (marketing).
3. Join form
| Paso | Comportamiento |
|---|---|
| Input focus | Border/ring énfasis |
| Validación | On submit (mínimo L1); campos required bloquean |
| Submit loading | Botón disabled + “Enviando…” opcional |
| Success path | Navigate /ok con code en state/query |
| Error path | Banner/texto error; form permanece |
| Campo | Input type / control |
|---|---|
| fullName | text |
| phone | tel |
| classType | select enum |
| preferredDay | date o text date |
| preferredSlot | text o select horas |
| notes | textarea |
4. Success
| Elemento | Interacción |
|---|---|
| Código | Seleccionable; copy-to-clipboard L1+ opcional |
| CTA home | Navigate / |
| Refresh | Debe seguir mostrando mensaje (state o re-fetch no aplica) |
5. Login
| Paso | Comportamiento |
|---|---|
| Submit | POST login |
| Success | Guardar token/user → /inbox |
| Error | Mensaje bajo form; password no se limpia necesariamente |
| Enter | Submit form |
6. Inbox
| Elemento | Interacción |
|---|---|
| Load | Parallel GET list + stats |
| Card click | Navigate /inbox/:id |
| Pull refresh | N/A web; botón reintentar en error |
| Empty | Mensaje centrado; sin CTA create (create es público) |
| Error | Mensaje + control reintentar (re-fetch) |
| Salir | Clear storage → /login |
Stats chips
Solo lectura en v1; click no filtra (filtro = L1+).
7. Request detail
| Elemento | Interacción |
|---|---|
| Volver | /inbox |
| Botones estado | PATCH inmediato; optimistic opcional; al 200 actualizar badge |
| Loading patch | Disable botones de acción |
| Error patch | Toast/texto; estado UI no miente |
| Email/tel | mailto: / tel: si se implementa (recomendado) |
Mapa de acciones sugerido
| Botón | Target status | Visible si |
|---|---|---|
| Marcar contactada | CONTACTED | status ≠ CONTACTED (o siempre) |
| Confirmar plaza | CONFIRMED | status ≠ CONFIRMED |
| Cancelar | CANCELLED | status ≠ CANCELLED |
[DECISIÓN DE DISEÑO]: L1 puede mostrar las tres acciones siempre; el PATCH acepta el enum completo.
8. Responsive
| Breakpoint | Comportamiento |
|---|---|
| < md | Nav colapsada; CTA header visible; grids 1 col |
| ≥ md | Nav links; home 2 col; inbox stats en fila |
9. Feedback y errores (copy interactivo)
| Situación | Feedback |
|---|---|
| Join OK | Navegación success (no solo alert) |
| Join fail | Inline error |
| Login fail | Inline error |
| Inbox fail | Panel error |
| Status OK | Badge actualiza |
10. Accesibilidad de interacción
- No usar solo hover para info crítica.
- Botones reales (
button/a), no div clickable sin role. - Mantener orden de tab natural en form y detail.
17-prototype-map.md
Abrir documento17 — Mapa de prototipo — VOLTA
1. Qué es “prototipo” en este case
| Capa | Rol |
|---|---|
| Paper | Hi-fi visual + UX process; no clicable nativo vía MCP |
| Angular app | Prototipo interactivo real (flujos E2E) |
| Docs | Flujos, IA, specs |
2. Paper → rutas
| Banda | Artboard | Ruta / estado |
|---|---|---|
| §2 | Home | / |
| §2 | Join | /apuntarme |
| §2 | Success | /ok |
| §3 | Login | /login |
| §3 | Inbox | /inbox |
| §3 | Detail | /inbox/:id |
| §4 | Mobile | mismas rutas, viewport 390 |
| §5 | Empty | /inbox sin rows |
| §5 | Error | API down / error flag |
Ver inventario completo: 00-paper-reference.md.
3. Flujos clicables en app
[Home] --Apuntarme--> [Join] --submit--> [Success] --inicio--> [Home]
[Home] --Coach------> [Login] --OK-----> [Inbox] --card--> [Detail] --status--> [Detail]
[Inbox] --Salir-----> [Login]
4. Datos del prototipo
| Fuente | Uso |
|---|---|
| Seed Neon | Inbox realista |
| POST create | Success con code nuevo |
| JWT | Barrera coach |
5. Limitaciones del prototipo v1
| Limitación | Nota |
|---|---|
| Paper no enlaza hotspots | Usar app para demo interactiva |
| Sin email real al coach | Contacto offline |
| Sin aforo | Confirmación manual |
| Token en localStorage | Demo |
6. Guión de demo (3 minutos)
- Home — eslogan, clases, promesa.
- Apuntarme — HIIT, día, 19:00, enviar.
- Success — mostrar
VO-…. - Login coach@volta.club / password123.
- Inbox — stats + lista seed + nueva.
- Detail Marc o la nueva — CONTACTED → CONFIRMED.
- (Opcional) empty/error si se demuestran estados.
7. Assets de prototipo
| Asset | Path |
|---|---|
| Hero case | 2026-08-08-volta/assets/hero.jpg |
| Hero app | volta-app/apps/web/src/assets/hero.jpg (o public) |
8. Criterio “prototype complete”
- Todos los must-have de flujo implementados en Angular
- Paper referencia bandas §1–§5
- Seed coherente con personas
- Microcopy ES sin lorem
18-completeness-audit.md
Abrir documento18 — Auditoría de completitud — VOLTA (2026-08-08)
1. Alcance auditado
Vertical slice L1: web club de barrio + solicitud pública de plaza + panel coach JWT, con docs, Paper, Angular+Nest+Prisma+Neon.
2. Checklist CRON / ALS-2
| Requisito | Estado | Evidencia |
|---|---|---|
| Diversidad sector/tipo/nivel | OK | Fitness L1; no marketplace; no agro/legal/logistics |
| Day brief + anti-patrones | OK | docs/00-day-brief.md |
| Paper bandas §1–§5 | OK | file 01KZG2VRQFF2QF0PRDB10D4AG7 |
| Docs 00–20 | OK | suite en docs/ |
| JWT coach | OK | Role COACH |
| API + seed + Neon | OK | delicate-mountain-11765167, port 3008 |
| Web Angular tokens | OK | Syne/Work Sans, chalk/ink/lime |
| Smoke public+coach | OK | plan doc 13 |
| Cierre sin deuda del L1 | OK | roadmap solo L1+/L2+ |
| Hipótesis no fake stats | OK | etiquetas en doc 02 |
3. Cobertura funcional
| Feature brief | Implementado | UI | API | Docs |
|---|---|---|---|---|
| Home | Sí | Sí | — | 01,09 |
| Join public | Sí | Sí | POST requests | 04,05 |
| Success | Sí | Sí | — | 04 |
| Login | Sí | Sí | POST login | 04,06 |
| Inbox + stats | Sí | Sí | GET + summary | 05 |
| Detail + status | Sí | Sí | GET + PATCH | 04 |
| Empty | Sí | Sí | — | 16 |
| Error red | Sí | Sí | — | 16 |
| Seed demo | Sí | — | seed | 05 |
4. Cobertura Paper
| Banda | Inventario | Notas |
|---|---|---|
| §1 UX | Cover→Datos | stakeholders, personas, JTBD, journey, blueprint, IA, datos |
| §2 DS+Public | DS, Home, Join, Success | tokens + cara pública |
| §3 Coach | Login, Inbox, Detail | panel JWT |
| §4 Mobile | Join/Inbox mobile | ~390px |
| §5 States | Empty, Error | resiliencia |
5. Rúbrica de calidad (auto SCORE orientativo)
| Eje | Score 1–5 | Comentario |
|---|---|---|
| Diversidad | 5 | Sector fitness nuevo en la serie |
| Craft visual | 4–5 | Palette lime/ink + Syne + hero |
| Densidad UX docs | 5 | Suite portfolio completa |
| Completitud código L1 | 4–5 | Vertical slice runnable |
| Authz | 5 | Guard en list/detail/status |
| Verdad investigación | 5 | Sin stats falsas |
6. Huecos aceptados (no regresiones de cierre)
| Hueco | Clasificación |
|---|---|
| Pagos / aforo live | Fuera L1 |
| e2e automatizado | Preferible L1+ |
| Route guards formales Angular | L1+ |
| Notificaciones email | Fuera L1 |
| Multi-coach | L2 |
7. Veredicto
COMPLETO para entrega de caso 2026-08-08 con documentación portfolio y app alineada al brief.
Cualquier ampliación multi-sede/pagos/marketplace requiere nuevo brief de diversidad, no parche silencioso.
19-backlog-completo.md
Abrir documento19 — Backlog completo — VOLTA
Inventario de ítems. Los del alcance L1 del día están Done.
El resto es opcional / siguiente nivel, no deuda oculta del cierre §1.1.
1. Done — L1 (2026-08-08)
| ID | Ítem | Capa |
|---|---|---|
| D01 | Definición producto VOLTA | Docs |
| D02 | Day brief diversidad fitness L1 | Docs |
| D03 | Personas Marc / Nora | Docs + Paper |
| D04 | JTBD + stories Must | Docs + Paper |
| D05 | IA y flujos | Docs |
| D06 | Modelo User/ClassRequest | Prisma |
| D07 | Auth JWT login coach | API + Web |
| D08 | POST solicitud pública | API + Web |
| D09 | Success + código VO- | Web |
| D10 | List requests + stats | API + Web |
| D11 | Detail + patch status | API + Web |
| D12 | Empty + error UI | Web |
| D13 | Home marketing multi-sección | Web |
| D14 | Seed demo + Neon | Data |
| D15 | Design tokens chalk/ink/lime | Web + Paper |
| D16 | Paper referencia §1–§5 | Docs + Paper |
| D17 | Suite docs 00–20 | Docs |
| D18 | README run 3008/4200 | Docs |
2. Backlog L1+ (misma complejidad, mejoras)
| ID | Ítem | Prioridad | Notas |
|---|---|---|---|
| B01 | canActivate guards Angular | P1 | UX auth |
| B02 | Filtros por status en inbox | P2 | Query opcional API |
| B03 | Captcha / rate limit POST | P1 | anti-spam |
| B04 | Confirm dialog cancel | P2 | |
| B05 | Toast de éxito | P3 | |
| B06 | Playwright smoke S1–S12 | P1 | CI |
| B07 | Skeleton loading | P3 | |
| B08 | mailto/tel en detail | P2 | ops |
| B09 | Checkbox privacidad | P1 | RGPD |
| B10 | Página 404 amigable | P3 | |
| B11 | API URL por environment | P1 | deploy |
3. Backlog L2 (requiere brief nuevo)
| ID | Ítem | Dependencia |
|---|---|---|
| C01 | Calendario clases + aforo | Schedule |
| C02 | Multi-coach asignación | FK coachId |
| C03 | Email transaccional | provider |
| C04 | Lookup público por código | authz acotada |
| C05 | Notas internas coach | schema |
| C06 | Export CSV | reporting |
| C07 | Roles ADMIN | permisos |
4. Backlog L3+ (explícito)
| ID | Ítem |
|---|---|
| E01 | Multi-sede tenant |
| E02 | Pagos cuotas |
| E03 | Push / app nativa |
| E04 | Marketplace multi-club |
5. Explicitamente no-backlog
| Idea | Razón |
|---|---|
| Marketplace de coaches | Fuera de VOLTA club único |
| ERP socios completo | Complejidad otra producto |
| Agro / legal / logistics | Otros cases de la serie |
6. Orden de ataque recomendado (si hay continuidad)
- B01 guards + B06 e2e + B11 env
- B08 contact shortcuts + B02 filtros
- B03 + B09 si hay tráfico real
- Evaluar brief L2 calendario
7. Trazabilidad
| Origen | Ítems |
|---|---|
| Day brief must-have | D01–D18 |
| Doc 15 roadmap next | B01–B11 |
| Doc 15 later | C01–C07, E01–E04 |
20-implementation.md
Abrir documento20 — Implementación — VOLTA
1. Resumen ejecutivo técnico
| Campo | Valor |
|---|---|
| App path | /Users/cristian/orca/volta-app/ |
| API | NestJS · puerto 3008 · prefijo /api |
| Web | Angular standalone · puerto 4200 |
| DB | Neon PostgreSQL · Prisma · delicate-mountain-11765167 |
| Auth | JWT Bearer · role COACH |
| Dominio | User, ClassRequest |
| Fecha | 2026-08-08 |
| GitHub | Criscode2022/volta-app (puede estar pendiente de push) |
2. Cómo arrancar
cd /Users/cristian/orca/volta-app
npm install --prefix apps/api
npm install --prefix apps/web
# Configurar apps/api/.env con DATABASE_URL y JWT_SECRET
npm --prefix apps/api run prisma:migrate # o script documentado en README app
npm --prefix apps/api run prisma:seed
npm run api # http://localhost:3008
npm run web # http://localhost:4200
Credenciales
| Rol | Password | |
|---|---|---|
| COACH | coach@volta.club | password123 |
3. Módulos API implementados
Auth
POST /api/auth/login- Valida email/password; compara bcrypt; emite JWT con
sub, email, role. JwtStrategy+JwtAuthGuardprotegen requests de lectura/escritura coach.
Requests
| Método | Ruta | Auth | Notas |
|---|---|---|---|
| POST | /api/requests | No | create público; status NEW; code VO- |
| GET | /api/requests | JWT | list createdAt desc |
| GET | /api/requests/stats/summary | JWT | total, open, byStatus |
| GET | /api/requests/:id | JWT | 404 si no existe |
| PATCH | /api/requests/:id/status | JWT | body { status } |
Prisma
Enums Role, RequestStatus, ClassType; modelos alineados a doc 05; migración init; seed 1 coach + 5 requests.
4. Frontend implementado
| Página | Responsabilidad |
|---|---|
| HomePage | marketing, hero, clases, horarios, footer |
| JoinPage | form create público |
| SuccessPage | confirmación + código |
| LoginPage | form → ApiService.login → navigate inbox |
| InboxPage | stats + list + empty/error + logout |
| RequestDetailPage | get + patch status |
ApiService centraliza base URL http://localhost:3008/api, token storage (volta_token, volta_user), métodos HTTP tipados (ClassRequest, stats, User).
5. Decisiones de implementación
| Decisión | Razón |
|---|---|
| Puerto API 3008 | Evitar colisión con otros daily apps |
| Soft auth en páginas | Simple L1; API sigue siendo autoridad |
| preferredDay/Slot String | Menos fricción timezone en L1 |
| Sin FK User–ClassRequest | Form anónimo |
| Código VO-MMDD-random | Referencia oral corta |
| Templates inline standalone | Velocidad daily; páginas autocontenidas |
| Stats endpoint propio | Evolución y menos lógica en cliente |
Ruta stats/summary antes de :id | Evitar captura de param |
6. Variables de entorno
| Variable | Servicio | Descripción |
|---|---|---|
DATABASE_URL | API | Neon connection string |
JWT_SECRET | API | Firma tokens |
PORT | API | opcional, 3008 |
Web: URL de API en ApiService (default localhost:3008).
7. Smoke de implementación (mínimo)
- Seed OK en consola (
VOLTA seed OK). - Login coach 200.
- List length ≥ 1.
- Create request 201 + code.
- Patch CONTACTED/CONFIRMED 200.
- GET sin token 401.
- Web muestra badges y home con Syne/lime.
8. Estructura de ficheros clave
volta-app/
├── apps/api/
│ ├── prisma/schema.prisma
│ ├── prisma/seed.ts
│ └── src/
│ ├── main.ts
│ ├── app.module.ts
│ ├── auth/
│ │ ├── auth.controller.ts
│ │ ├── auth.service.ts
│ │ ├── jwt.strategy.ts
│ │ └── jwt-auth.guard.ts
│ ├── requests/
│ │ ├── requests.controller.ts
│ │ └── requests.service.ts
│ └── prisma/
├── apps/web/
│ ├── tailwind.config.js
│ └── src/app/
│ ├── app.routes.ts
│ ├── core/api.service.ts
│ └── pages/
│ ├── home/
│ ├── join/
│ ├── success/
│ ├── login/
│ ├── inbox/
│ └── request-detail/
└── package.json
9. Alineación case ↔ app
| Doc | Evidencia en código |
|---|---|
| 05 data model | schema.prisma enums y models |
| 04 flows | routes + controller methods |
| 08 DS | tailwind colors + fontFamily |
| 09 content | strings en templates home/join/… |
| 00 paper | URLs en README case |
10. Notas de cierre técnico
- Vertical slice L1 runnable local con Neon.
- No quedan features must-have del brief sin implementar.
- Mejoras (guards Angular, e2e, rate limit) viven en backlog L1+, no como deuda de cierre del día.