00-day-brief.md
00 — Day brief · 2026-08-21 · TEMPLE
Decisiones ALS-2 BRIEF
| Campo | Valor |
|---|---|
| Fecha | 2026-08-21 |
| Nombre | TEMPLE |
| Complejidad | Nivel 2 (no L1 consecutivo tras PREGÓN) |
| Sector | Música / local de ensayo de barrio (nave Carabanchel) |
| Tipo | Quiosco de horas + tablero CONSERJE JWT (no entradas, no concierto) |
| Plataforma | Web kiosk-first (pantalla en el pasillo · mesa conserje desktop) |
| Registro | R-HY — portada de local clásica + herramienta de horas (no 2× R-IN) |
| Shell | S-MIN — casi sin nav; el quiosco es una acción |
| Home | H-KIOSK — tres salas enormes; no hero 2-col, no chat, no bento |
| Flujo | F-BOOK — coger un bloque de 2 h; no kanban, no editor |
| Por qué no PREGÓN | No S-SIDE / H-CHAT / F-KAN; no admin pública |
| Por qué no MATIZ | No S-BOTTOM / H-BENTO / F-EDIT; no belleza |
| Por qué no Conciergo | Ensayo ≠ concierto; TEMPLE no vende entradas |
Terna unicidad
R-HY · S-MIN · H-KIOSK · F-BOOK
0 códigos iguales a N−1 (PREGÓN: R-IN · S-SIDE · H-CHAT · F-KAN).
≥2 distintos vs N−2 (MATIZ) y N−3 (ZAGUÁN).
Ventana 4: R-IN + R-HY + R-IN + R-CL → hoy R-HY (sigue habiendo clásico).
S-MIN, H-KIOSK y F-BOOK no están en los últimos 5 (S-SIDE/BOTTOM/WIZ/TOP/RAIL · H-CHAT/BENTO/WIZARD/GALLERY/TABLE · F-KAN/EDIT/CMP/STORY/LEAD).
Ground (CRON §5.6)
- Familia: G-INK
- Hex:
#12110F - Por qué: cuadro de instrumentos de un quiosco en el pasillo (vehicle dashboard), no fotocopia (PREGÓN), no yeso (MATIZ), no hormigón (ZAGUÁN), no kiosco blanco (MARGEN), no musgo (CESTA).
Mood visual (Paper)
- Candidatos: nocturnal (primer instinto concierto), vehicle dashboard, subterranean, industrial, phosphor
- Elegido: vehicle dashboard — no el primer instinto escenario+neón (eso es Conciergo). Un local de ensayo se opera como un tablero de horas, ámbar LED sobre negro de flight case.
- Paleta:
#12110Finstrument black (ground)#1E1C18panel#F4EBD0crema de dial#E8A317ámbar LED / gaffer#8C8474mute#C23B22joya de ampli (urgente, poco)
- Tipo: Fraunces display · Atkinson Hyperlegible UI (evita Ibarra+Jost / Libre Baskerville+Nunito / Instrument+Sora / Cormorant+Public Sans / Spectral+Manrope)
Alcance L2 must
- Home kiosk: 3 salas a pantalla completa (lead + 3 datos)
- Rejilla de horas (bloques de 2 h, hoy)
- Confirmar con nombre de banda (sin cuenta)
- Ticket (hora cogida ≠ concierto)
- Login JWT CONSERJE
- Tablero de ocupación de hoy (horario, no kanban)
- Empty / error / loading / mobile kiosk
- ≥12 UX + ≥10 UI
Microcopy duro
- Hora cogida ≠ concierto. TEMPLE no vende entradas.
- Sala ≠ escenario. Es un cuarto con moqueta.
- TEMPLE no actúa. El concierto es otro producto.
- Ensayar no es tocar en público.
Supuestos
- S1: Una nave atiende 12–20 horas/día en 3 salas; la demo tiene 3 salas y 5 bloques (10–12, 12–14, 16–18, 18–20, 20–22).
- S2: El músico coge hora en el pasillo, con la funda en el suelo; no crea cuenta.
- S3: Un CONSERJE (Lola) ve ocupación; no hay taquilla.
- S4: Sin backline extra, sin rider, sin pago en el kiosk (se paga en ventanilla). [DECISIÓN]
Hipótesis
| ID | Señal |
|---|---|
| H1 | Un quiosco de 3 salas reduce “¿está libre la 2?” por WhatsApp |
| H2 | Separar hora de concierto evita la expectativa de entradas |
| H3 | Bloques fijos de 2 h bastan; el músico no necesita login |
00-paper-reference.md
Paper reference · TEMPLE
| URL | https://app.paper.design/file/01M0HJ2Z7NJSYC0FDMWYSSQBG3 |
| File ID | 01M0HJ2Z7NJSYC0FDMWYSSQBG3 |
UX-count: 12 UI-count: 12
UX-00 Cover · UX-01 Stakeholders · UX-02 Personas · UX-03 JTBD · UX-04 Stories · UX-05 Journey · UX-06 Blueprint · UX-07 Site map · UX-08 Flujos · UX-09 Datos+permisos · UX-10 Métricas · UX-11 Research UI-00 Tokens · UI-01 Kiosk home · UI-02 Kiosk mobile · UI-03 Slots · UI-04 Confirm · UI-05 Success · UI-06 Login · UI-07 Turno · UI-08 Empty · UI-09 Error · UI-10 Loading · UI-11 Slots mobile
UX process (prefijo UX- · mínimo 12)
| ID | Nombre | Contenido |
|---|---|---|
| UX-00 | Cover | TEMPLE · «La hora, no el concierto.» · R-HY · S-MIN · H-KIOSK · F-BOOK · L2 música ensayo · vehicle dashboard · 2026-08-21 |
| UX-01 | Stakeholders | BANDA (Iván), CONSERJE (Lola), nave, Conciergo fuera de alcance |
| UX-02 | Personas | Iván Mora 29 · Lola Rivas 47 · Marta Chen 34 (batería) |
| UX-03 | JTBD | Job «coger Sala 2 dos horas sin preguntar por WhatsApp» |
| UX-04 | Stories | Must: kiosk, horas, ticket, login, turno, estados |
| UX-05 | Journey | Llega con la funda → toca sala → hora → ticket → (Lola) ve ocupación |
| UX-06 | Blueprint | Frontstage kiosk · backstage llaves · Nest/Neon/JWT |
| UX-07 | Site map | Público / kiosk · /ok/:code · /login · /turno |
| UX-08 | Flujos | F-BOOK público; F-TURNO CONSERJE |
| UX-09 | Datos | User CONSERJE · Room · Booking; JWT en turno |
| UX-10 | Métricas | North star % bloques ocupados sin WhatsApp |
| UX-11 | Research | Comprobado / supuesto / hipótesis / decisión |
UI producto (prefijo UI- · mínimo 10)
| ID | Nombre | Flujo |
|---|---|---|
| UI-00 | Tokens | DS dashboard: ink, panel, cream, amber, mute, jewel |
| UI-01 | Kiosk home | H-KIOSK 1440: 3 salas enormes. Lead + 3 datos |
| UI-02 | Kiosk mobile | 390: mismas 3 salas |
| UI-03 | Slots | Bloques 2 h de hoy |
| UI-04 | Confirm | Nombre de banda |
| UI-05 | Success | Ticket. Hora ≠ concierto |
| UI-06 | Login | JWT CONSERJE |
| UI-07 | Turno | Ocupación de hoy (horario, no kanban) |
| UI-08 | Empty | Sin horas / sin salas |
| UI-09 | Error | Red |
| UI-10 | Loading | Skeletons |
| UI-11 | Slots mobile | Rejilla en 390 |
Mapeo Paper → Angular
| Artboard | Ruta | Componente |
|---|---|---|
| UI-01 Kiosk | / | KioskPage |
| UI-03 Slots | /sala/:slug | SlotsPage |
| UI-05 Success | /ok/:code | OkPage |
| UI-06 Login | /login | LoginPage |
| UI-07 Turno | /turno | TurnoPage |
01-project-definition.md
01 — Definición de proyecto — TEMPLE
1. Identidad
| Campo | Valor |
|---|---|
| Nombre | TEMPLE |
| Significado | Temple es el recinto de ensayo, no el recinto de concierto. Ni la taquilla ni el escenario. Se entra al quiosco; se sale con una hora. |
| Eslogan | «La hora, no el concierto.» |
| Una frase | Quiosco de horas + tablero CONSERJE JWT (horario de ocupación de hoy). |
| Sector | Música / local de ensayo de barrio (nave Carabanchel) |
| Tipo | Web L2 — kiosk-first + rejilla de 2 h + ticket + turno — Nivel 2, herramienta de horas usable |
| Plataforma | Web kiosk-first (pantalla en el pasillo · mesa conserje desktop) |
| Mercado demo | España · Madrid · Carabanchel · Paseo de Yeserías (una nave, no una red) |
| Idioma | es-ES |
| Fecha caso | 2026-08-21 |
| Terna | R-HY · S-MIN · H-KIOSK · F-BOOK |
[COMPROBADO] Nombre, terna, nivel, sector, ground y paleta salen de docs/00-day-brief.md.
[SUPUESTO de catálogo] Paseo de Yeserías / Carabanchel es atrezzo de mercado, no la dirección de un local real.
2. Problema
Principal (hipótesis de diseño)
[HIPÓTESIS] El músico de un local de ensayo de barrio no necesita taquilla: necesita coger Sala 2 dos horas sin preguntar por WhatsApp. Hoy eso vive en un grupo, una conserje con llaves y una expectativa de escenario. La hora se lee como concierto; la sala se lee como escenario; el producto se lee como Conciergo. [SUPUESTO] Una nave atiende 12–20 horas/día en 3 salas; no opera un ticketing ni un 112.
Secundarios
| Problema | Quién lo sufre | Efecto |
|---|---|---|
| «¿Está libre la 2?» por WhatsApp | BANDA (Iván) | Espera, funda en el suelo, llega y está cogida |
| Hora se lee como concierto | BANDA + nave | Esperan entrada, aforo, taquilla |
| Sala se lee como escenario | BANDA + público | Luces, palco, «tocamos esta noche» |
| El kiosk se lee como 112 | CONSERJE + nave | Urgencia vital en un canal de horas |
| El tablero se lee como kanban | CONSERJE (Lola) | Esperan Recibido / En curso / Cerrado |
| La dueña pide TPV y entradas el día 1 | Nave | El L2 se vuelve Conciergo |
Supuestos (no investigación primaria propia)
- S1: Una nave atiende 12–20 horas/día en 3 salas; la demo tiene 3 salas y 5 bloques (10–12, 12–14, 16–18, 18–20, 20–22). [SUPUESTO]
- S2: El músico coge hora en el pasillo, con la funda en el suelo; no crea cuenta. [SUPUESTO]
- S3: Un CONSERJE (Lola) ve ocupación; no hay taquilla. [SUPUESTO]
- S4: Sin backline extra, sin rider, sin pago en el kiosk (se paga en ventanilla). [DECISIÓN]
Hipótesis de producto
| ID | Hipótesis | Señal de validación (futura) |
|---|---|---|
| H1 | Un quiosco de 3 salas reduce “¿está libre la 2?” por WhatsApp | % de visitas a / que terminan en POST con código |
| H2 | Separar hora de concierto evita la expectativa de entradas | ↓ «pensé que era una entrada»; copy visible en ticket |
| H3 | Bloques fijos de 2 h bastan; el músico no necesita login | 0 cuentas de banda; Lola ve ocupación sin chat |
No se afirman estadísticas de locales de ensayo inventadas. Todo lo anterior es razonamiento de diseño etiquetado.
3. Propuesta de valor
| Para | Valor |
|---|---|
| BANDA (Iván Mora · Los Yesos) | Toca Sala 2, coge 18–20, escribe el nombre de la banda, se lleva un código. Nadie le pide cuenta ni entrada. |
| CONSERJE (Lola Rivas) | Ve el horario de hoy. Quién ocupa cada bloque. No mueve columnas. No vende entradas. |
| BATERÍA (Marta Chen) | Misma superficie que Iván. La de batería a las cuatro ya está en el seed. |
| Nave TEMPLE | Un quiosco mínimo: salas + horas + turno, sin Conciergo y sin 112. |
No es TEMPLE
| Excluido | Por qué |
|---|---|
| Entradas / taquilla / aforo | Hora cogida ≠ concierto |
| Escenario / palco / luces de concierto | Sala ≠ escenario |
| Conciergo / ticketing | TEMPLE no vende entradas |
| «Ya estáis tocando» al coger hora | Ensayar no es actuar |
| 112 / urgencia vital | TEMPLE no es 112 |
| Chat de incidencias / kanban | Eso fue PREGÓN (H-CHAT / F-KAN) |
| Cuaderno de fórmulas / Hoy bento | Eso fue MATIZ (H-BENTO / F-EDIT) |
| Wizard de fincas + comparador | Eso fue ZAGUÁN (H-WIZARD / F-CMP) |
| Lookbook / masthead editorial | Eso fue MARGEN (H-GALLERY / F-STORY) |
| Hero 2-col + 3 cards de «tu local» | Anti-patrón AP-12; contradice H-KIOSK |
| Pago en kiosk / pasarela | S4: se paga en ventanilla |
| Backline extra / rider | S4 |
| App de 40 salas y calendario semanal | L2 compacto, no PMS de red |
4. Objetivos
Negocio / caso de estudio
- Demostrar vertical slice L2 música / ensayo de barrio con Room + Booking + JWT CONSERJE.
- Portfolio coherente: Paper (12 UX + 12 UI) + docs + app runnable.
- Terna R-HY · S-MIN · H-KIOSK · F-BOOK frente a PREGÓN (chat/kanban), MATIZ (bento/editor) y ZAGUÁN (wizard/comparador).
Usuario
| Rol | Objetivo medible en demo |
|---|---|
| BANDA | Ver 3 salas, coger un bloque y ver el código en < 60 s, sin cuenta |
| CONSERJE | Entrar a turno, ver horario 8/15, leer Marta Chen en Sala 1 16–18 en < 45 s |
| BATERÍA | Misma superficie; no encuentra login de banda ni kanban |
No objetivos v1 (explícitos)
- Entradas, taquilla, aforo, Conciergo
- Escenario, palco, line-up, rider
- 112, policía, bomberos
- Chat, kanban, columnas Recibido / En curso
- Cuenta de banda, seguimiento con login, push
- Pago en kiosk, TPV, pasarela
- Calendario semanal / mes
- Multi-nave, multi-conserje
- App nativa ni notificaciones push
- Rol DUEÑA autenticado
5. Roles y permisos (resumen)
| Acción | Anónimo (banda) | CONSERJE | Taquilla / 112 |
|---|---|---|---|
| Ver kiosk / salas | Sí | Sí | No hay cuenta |
| POST hora | Sí | Sí (no es el job) | No |
Ver ticket /ok/:code | Sí (código en URL) | Sí | — |
| Ver turno | No (401 / redirect) | Sí | No |
GET /api/turno | 401 | Sí | — |
| Ver nombre de otras bandas en kiosk | No (solo libre / cogida) | Sí (horario) | — |
| Vender entrada | No (no existe) | No | Fuera |
| Llamar al 112 | Copy: fuera | Copy: fuera | El 112 |
[DECISIÓN] Un solo rol autenticado: CONSERJE. El músico no es un usuario del sistema: es autora/autor de un booking. La taquilla no es un rol de sistema el día 1.
6. Métricas (modelo, no instrumentadas en v1 salvo base)
| Tipo | Métrica | Definición |
|---|---|---|
| North Star | % de bloques ocupados sin WhatsApp | Oficio de pasillo, no pageviews |
| Activación banda | 1.er POST con code | H1 |
| Integridad de expectativa | Reclamaciones «¿dónde está mi entrada?» / «¿es el escenario?» / «¿es el 112?» | H2 + microcopy |
| Integridad de auth | GET /api/turno sin token → 401; POST /api/bookings sin token → 201 | Kiosk público + turno cerrado |
| Salud | Error rate API rooms / bookings | 4xx/5xx |
7. Alcance funcional v1 (L2)
| Módulo | Incluido |
|---|---|
| Kiosk | GET /api/rooms · 3 salas enormes (lead + 3 datos) |
| Horas | GET /api/rooms/:slug · bloques de 2 h de hoy |
| Confirmar | Nombre de banda (sin cuenta) |
| Ticket público | POST /api/bookings · { roomSlug, slot, bandName } → TM-XXXX CONFIRMED |
| Auth | POST /api/auth/login → JWT CONSERJE |
| Turno | GET /api/turno JWT · horario de ocupación de hoy |
| Estados UI | Empty (0 salas / 0 horas), loading skeleton, error de red, 409 slot cogido |
| Mobile | Kiosk ~390px · rejilla de horas · targets ≥44px |
| Seed | 1 CONSERJE, 3 salas, 8 horas (8/15) |
| Salud | GET /api/health → { ok: true, service: "temple-api" } |
8. Criterios de aceptación de producto
/es el kiosk de 3 salas. No pide cuenta. No es un hero 2-col + 3 cards.- Un músico puede ver 3 salas en el fold (lead + 3 datos), tocar Sala 2, coger 18–20 y obtener un código
TM-XXXX. /ok/:codedice explícitamente que hora cogida no es concierto y que TEMPLE no vende entradas.- La UI dice explícitamente que sala no es escenario y que ensayar no es actuar.
- Sin token, GET
/api/turnoresponde 401. POST/api/bookingsy GET/api/roomsson públicos. - Un POST de hora crea
status=CONFIRMED. Coger no emite una entrada. - Una CONSERJE inicia sesión y ve el horario con 8 cogidas / 7 libres en el seed.
- El tablero es un horario (filas = bloques, columnas = salas). No es un kanban de 3 columnas.
- Fotos reales en las 3 salas seed (assets
salas/*). - Bloques visibles: 10–12 · 12–14 · 16–18 · 18–20 · 20–22.
- Chrome S-MIN: casi sin nav. Kiosk público sin top-nav de marketing.
- Rutas solo las del doc 03. No existen
/entradas,/concierto,/112,/mesa,/chat. GET /api/healthdevuelveservice: "temple-api".- El kiosk no muestra el nombre de otras bandas; el turno sí.
9. Stack y artefactos
| Capa | Detalle |
|---|---|
| Frontend | Angular + Tailwind · puerto 4200 |
| Backend | NestJS · puerto 3021 |
| DB | Neon PostgreSQL · project divine-haze-05909195 |
| Auth | JWT (CONSERJE) |
| Diseño | Paper 01M0HJ2Z7NJSYC0FDMWYSSQBG3 |
| Repo app | /Users/cristian/orca/temple-app/ · GitHub Criscode2022/temple-app |
[COMPROBADO] Puerto, Neon, Paper file ID, repo y path de app constan en el encargo.
El código se escribe en paralelo a esta suite.
10. Riesgos y mitigaciones
| Riesgo | Impacto | Mitigación v1 |
|---|---|---|
| Expectativa de entrada | «¿Dónde está mi ticket de concierto?» | Copy «Hora cogida ≠ concierto» · «TEMPLE no vende entradas» |
| Expectativa de escenario | Luces, palco, público | Copy «Sala ≠ escenario» |
| Expectativa de 112 | Urgencia vital en el kiosk | Copy «TEMPLE no es 112» |
| Expectativa de kanban | Recibido / En curso | Horario, no columnas de estado |
| Pago en kiosk el día 1 | Alcance L3 disfrazado | S4: ventanilla |
| Cuenta de banda | Rompe S2 / H3 | Sin signup; nombre libre en el booking |
| Home percibida como landing de sala de conciertos | Pérdida de H-KIOSK / AP-12 | Las 3 salas son la home; no hero 2-col |
| Confundir con PREGÓN (chat + kanban) | Expectativa de parte | Kiosk de salas; no hilo |
| Confundir con Conciergo | Expectativa de entradas | Microcopy ×4 |
| Double-book del mismo bloque | Dos bandas a la misma hora | Unique (room, day, slot) · 409 |
| Enumeración de horas por código | PII de banda en público | GET turno JWT; /ok/:code no hidrata ficha ajena |
| 0 salas | Kiosk vacío sin oficio | Empty «Aún no hay salas.» |
| WhatsApp paralelo | H1 no se mide | North star etiquetada como modelo |
11. Glosario
| Término | Definición en TEMPLE |
|---|---|
| Temple | Recinto de ensayo; el producto, no un concierto |
| Sala | Cuarto con moqueta (rooms); no es un escenario |
| Escenario | Superficie de concierto; fuera |
| Hora / bloque / slot | Tramo fijo de 2 h; 10-12 … 20-22 |
| Hora cogida | POST 201 + código; no significa concierto |
| Ticket | Acuse de hora (TM-XXXX); no es una entrada |
| Entrada | Ticket de concierto; fuera. TEMPLE no vende entradas |
| Quiosco / kiosk | Superficie H-KIOSK pública del pasillo |
| Turno | Superficie de ocupación de la CONSERJE (horario) |
| Kanban | Lenguaje de diseño de otros días; no hay columnas aquí |
| CONSERJE | Usuario autenticado que opera el turno |
| BANDA | Autora/autor de la hora; no tiene fila en users |
| Ventanilla | Pago fuera de la app (S4) |
| Ink | Ground #12110F |
| Panel | Superficie #1E1C18 |
| Cream | Dial #F4EBD0 |
| Amber | LED / gaffer #E8A317 |
| Mute | Meta #8C8474 |
| Jewel | Acento de ampli #C23B22, poco |
| 112 | Emergencia vital; fuera |
| Conciergo | Producto de entradas; fuera |
12. Decisiones de diseño (cierre de brief)
| ID | Decisión | Alternativa descartada |
|---|---|---|
| D1 | Home = 3 salas enormes (H-KIOSK) | Hero 2-col + 3 cards (AP-12) · chat (PREGÓN) · bento (MATIZ) · wizard (ZAGUÁN) |
| D2 | Shell mínimo (S-MIN) | Rail de estados · bottom tabs · masthead · wizard chrome |
| D3 | Registro híbrido vehicle dashboard (R-HY) | Escenario+neón (primer instinto; Conciergo) · highlighter PREGÓN |
| D4 | Flujo F-BOOK (coger un bloque de 2 h) | F-KAN, F-EDIT, F-CMP, F-STORY, F-CHAT |
| D5 | Mood vehicle dashboard | Nocturnal concierto (primer instinto), highlighter, chapel, rusted |
| D6 | Un rol autenticado CONSERJE | Multi-rol dueña / taquilla / banda / 112 |
| D7 | Status de hora CONFIRMED | Kanban de 3 columnas; HOLD; «en escenario» |
| D8 | Banda sin cuenta | Signup, seguimiento con login |
| D9 | Kiosk no filtra nombres de otras bandas | Tablero público enumerabile |
| D10 | POST público { roomSlug, slot, bandName } | Formulario de rider + pago + DNI |
| D11 | Ground G-INK #12110F | G-FOG, G-CHAPEL, G-CONCRETE, G-GALLERY, G-MOSS |
| D12 | Success de ticket en /ok/:code | Toast único sin pantalla |
| D13 | 5 bloques fijos de hoy, sin 14–16 | Calendario semanal; slots de 30 min |
| D14 | Turno = horario, no kanban | Recibido / En curso / Cerrado |
| D15 | Kiosk público + turno JWT (no auth-first total) | Todo cerrado (rompería S2) · todo abierto (rompería turno) |
| D16 | Pago en ventanilla | Pasarela en kiosk |
| D17 | Unique (room_id, day, slot) | Overbooking «por si acaso» |
13. Relación con el día anterior
| Case | Terna | Por qué TEMPLE no lo copia |
|---|---|---|
| PREGÓN (N−1) | S-SIDE / H-CHAT / F-KAN | No admin pública, no chat, no kanban, no 112 |
| MATIZ (N−2) | S-BOTTOM / H-BENTO / F-EDIT | No belleza, no PWA de oficio, no editor de gramos |
| ZAGUÁN (N−3) | S-WIZ / H-WIZARD / F-CMP | No inmobiliaria, no wizard, no comparador |
| MARGEN (N−4) | S-TOP / H-GALLERY / F-STORY | No editorial, no lookbook, no masthead |
[COMPROBADO] El brief fija terna R-HY · S-MIN · H-KIOSK · F-BOOK. 0 códigos iguales a N−1 (PREGÓN). ≥2 distintos vs N−2 (MATIZ) y N−3 (ZAGUÁN). Ventana 4 días: R-IN + R-HY + R-IN + R-HY. Ground G-INK #12110F, no G-FOG.
02-ux-research-strategy.md
02 — Estrategia de investigación UX — TEMPLE
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].
1. Objetivos de investigación (del caso)
| Objetivo | Método en este caso | Salida |
|---|---|---|
| Entender actores de la nave | Modelado de stakeholders + personas | §3–4 |
| Definir job de «coger Sala 2 dos horas» y de ver ocupación | JTBD + stories Must | §5 |
| Mapear fricción WhatsApp / taquilla / escenario → kiosk | Journey + service blueprint | §6–7 |
| Traducir a requisitos L2 kiosk + turno | Matriz hallazgo → requisito → feature | §8 |
2. Fuentes y límites
Fuentes admisibles (secundarias / operativas)
- Conocimiento general de locales de ensayo de barrio (salas con kit / combo / seca; bloques de 2 h; llaves; pago en ventanilla; distinción ensayo vs concierto).
- Analogía operativa con kiosk público + panel JWT de la serie daily.
- Restricciones ALS-2: no Conciergo, no taquilla, no 112, no kanban, no chat, no editor de oficio.
Límites éticos de verdad
| Prohibido | Permitido |
|---|---|
| «El 62% de bandas de Carabanchel reserva por WhatsApp» sin fuente | «[SUPUESTO] Iván llega con la funda y pregunta si está libre la 2» |
| Citas de entrevistas ficticias como campo real | Quotes de persona etiquetadas como constructo de diseño |
| Volumen medido «17 horas/día en Yeserías» como KPI de mercado | Horas de seed de producto, etiquetadas como demo |
| Horario oficial de una nave concreta de Carabanchel | Turno de seed; Lola, Iván y Marta son personas de diseño |
| «Iván existe y nos dijo…» | Iván Mora es persona de diseño |
3. Stakeholders
| Stakeholder | Influencia | Interés | Necesidad principal |
|---|---|---|---|
| BANDA (Iván) | Alta en la hora | Muy alta | Coger Sala 2 dos horas sin cuenta ni WhatsApp |
| CONSERJE (Lola) | Alta | Muy alta | Ver quién ocupa cada bloque de hoy |
| BATERÍA (Marta) | Media | Alta | Misma rejilla; la de batería a las cuatro |
| Nave / dueña | Alta formal, baja en producto día 1 | Alta | Que se ocupen bloques; que no se confunda con concierto |
| Taquilla / Conciergo | Competencia / analogía falsa | — | Fuera de alcance; no clonar entradas |
| 112 / emergencias | Alta en emergencias | — | Fuera de alcance; no clonar el canal |
| Grupo de WhatsApp de la nave | Canal paralelo | — | No es el backoffice |
| Público de concierto | — | — | No es usuario; TEMPLE no actúa |
Mapa de poder (resumen)
- Decisor de adopción: la nave (quién pone el kiosk en el pasillo) y, en uso diario, Lola (quien mira el horario).
- Usuario frecuente de coger hora: BANDA / BATERÍA (kiosk, sin cuenta).
- Usuario frecuente de ocupación: CONSERJE (turno).
- Riesgo de rechazo: si el ticket parece una entrada; si la sala parece escenario; si hay que crear cuenta; si el turno parece un kanban.
4. Personas
P1 — Iván Mora · BANDA (guitarra, Los Yesos)
| Campo | Detalle |
|---|---|
| Edad / contexto | 29 años; guitarra; banda Los Yesos; ensaya en nave de Carabanchel |
| Digital | Móvil con funda en el suelo; no quiere «otra cuenta de sala»; no compra entradas aquí |
| Goals | Coger Sala 2 dos horas; llevarse un código; no preguntar por WhatsApp |
| Pains | El grupo dice «creo que está libre»; llega y está cogida; le venden un concierto |
| Quote de diseño | «Solo quiero la 2 a las seis. No me vendas un concierto.» |
Escenario: Abre / en el kiosk del pasillo, toca Sala 2 Combo, elige 18–20, escribe Los Yesos, lee «Hora cogida ≠ concierto» y el código TM-XXXX.
[COMPROBADO] Nombre, edad y gesto (guitarra, Los Yesos) salen del encargo. Es constructo de diseño, no entrevistado. [DECISIÓN]
P2 — Lola Rivas · CONSERJE
| Campo | Detalle |
|---|---|
| Edad / contexto | 47 años; conserje de la nave; turno de llaves y ocupación |
| Digital | Fluida en desktop de mesa; el kiosk del pasillo no es su herramienta |
| Goals | Ver el horario de hoy, saber quién tiene cada bloque, dar las llaves (fuera de app) |
| Pains | WhatsApp a deshora; «¿está libre la 2?»; un kanban que no es su oficio; taquilla que no es su job |
| Quote de diseño | «Quiero ver quién ocupa cada hora. No un kanban.» |
| Email demo | lola@temple.nave / password123 |
Escenario: Login → turno horario 8/15 → lee Marta Chen en Sala 1 16–18 → no encuentra «entradas» ni «112» ni columnas Recibido / En curso.
[COMPROBADO] Credencial demo sale del encargo. Nombre, edad y mesa son constructo de diseño. [DECISIÓN]
P3 — Marta Chen · BATERÍA (secundaria)
| Campo | Detalle |
|---|---|
| Edad / contexto | 34 años; batería; coge Sala 1 porque hay kit |
| Digital | Alta; escribe rápido; no necesita onboarding |
| Goals | Dejar la de batería apuntada; no montar un rider |
| Pains | Formularios de backline; «regístrate para reservar»; calendario de 30 días |
| Quote de diseño | «La de batería a las cuatro. Sin rider.» |
Escenario: En el seed ya ocupa Sala 1 Batería 16–18. No entra a /turno. Misma superficie que Iván.
[DECISIÓN] Marta no es rol de sistema. Es la misma superficie que Iván, con otra sala. En seed figura como bandName «Marta Chen».
Bandas de seed (no personas primarias extra)
| Nombre | Rol en seed | Código |
|---|---|---|
| Marta Chen | P3 · Sala 1 16–18 | TM-2104 |
| Cuarto Aire | Catálogo | TM-2101, TM-2108 |
| Tres Cables | Catálogo | TM-2102, TM-2107 |
| Papel Fumado | Catálogo | TM-2103 |
| Las Cajas | Catálogo | TM-2105 |
| Eco Bajo | Catálogo | TM-2106 |
| Los Yesos | P1 · no en seed (POST demo) | — |
[COMPROBADO] Nombres de persona salen del encargo. Los nombres de banda extra son catálogo demo. [SUPUESTO de catálogo]
Anti-personas
| Quién | Por qué no es target v1 |
|---|---|
| Promotor de Conciergo | S3: no hay taquilla ni entradas |
| Público que quiere «entradas de esta noche» | TEMPLE no vende entradas |
| Quién llama por un infarto | TEMPLE no es 112 |
| Operadora de PREGÓN que espera 3 columnas | Otro job, otro día |
| Colorista de MATIZ que espera Hoy bento | Otro job, otro día |
| Dueña que quiere TPV y 12 salas el día 1 | H3 / S1: 3 salas, 5 bloques |
| Banda que quiere rider y backline extra | S4 |
5. JTBD y user stories
Job principal (BANDA)
Cuando llego al pasillo con la funda y no sé si está libre la 2,
quiero coger Sala 2 dos horas en el quiosco,
para no preguntar por WhatsApp ni crear una cuenta.
Job principal (CONSERJE)
Cuando abro el turno por la tarde,
quiero ver quién ocupa cada bloque de las tres salas,
para no cazar horas en un grupo de WhatsApp.
Job secundario (BATERÍA)
Cuando necesito el kit,
quiero ver Sala 1 y sus bloques de hoy,
para no montar un rider ni un escenario.
Jobs secundarios
| Job | Rol |
|---|---|
| Distinguir hora de concierto | BANDA / CONSERJE |
| Entender que no es taquilla | BANDA / nave |
| Entender que la sala no es escenario | BANDA / nave |
| No crear cuenta | BANDA |
| Ver ocupación de hoy como horario | CONSERJE |
| No ver nombres ajenos en el pasillo | BANDA (D9) |
Stories Must (v1)
| ID | Story | AC |
|---|---|---|
| US1 | Como músico, quiero ver las 3 salas sin cuenta | GET /api/rooms · lead + 3 datos en el fold |
| US2 | Como músico, quiero ver los bloques de 2 h de hoy | GET /api/rooms/:slug · 5 slots |
| US3 | Como músico, quiero confirmar con el nombre de la banda | UI-04 · POST bandName |
| US4 | Como músico, quiero un código al coger | POST → TM-XXXX · /ok/:code |
| US5 | Como músico, quiero que el ticket no sea una entrada | Copy hora ≠ concierto · no vende entradas |
| US6 | Como conserje, quiero entrar con email/password | JWT + redirect /turno |
| US7 | Como conserje, quiero ver el horario de hoy | GET /api/turno · 8/15 en seed |
| US8 | Como conserje, quiero leer el nombre de la banda en cada celda | Horario, no kanban |
| US9 | Como cualquiera sin token, no quiero ver el turno | 401 / redirect login |
| US10 | Como músico, no quiero ver el nombre de otras bandas en el kiosk | Slots free / taken |
| US11 | Como músico o conserje, quiero empty / error / loading | UI-08, UI-09, UI-10 |
| US12 | Como músico en el pasillo, quiero targets ≥44px | Kiosk 390 + UI-11 |
| US13 | Como músico, quiero que un bloque cogido no se pueda volver a coger | 409 + unique |
MoSCoW (v1 L2)
| Prioridad | Ítems |
|---|---|
| Must | Kiosk 3 salas, rejilla de horas, confirmar, ticket, login, turno horario, estados, empty/error/loading, kiosk mobile, unique slot |
| Should | Ghost Turno en kiosk; pie «no vende entradas»; logout en turno; 409 en UI |
| Could | GET /api/me; cancelar hora CONSERJE; grey de bloques pasados; ?day= |
| Won’t | Cuenta de banda, entradas, 112, kanban, chat, pago kiosk, calendario semanal, rider |
6. Journey (BANDA · Sala 2 a las seis + CONSERJE)
| Fase | Actor | Acción | Touchpoint | Emoción [HIPÓTESIS] |
|---|---|---|---|---|
| 1 Ver las salas | Iván | Abre /; lee 3 salas (lead + 3 datos) | Kiosk H-KIOSK | Oficio, «esto no es taquilla» |
| 2 Elegir sala | Iván | Toca Sala 2 Combo | /sala/combo | Concentración (funda, pasillo) |
| 3 Elegir hora | Iván | Toca 18–20 (libre) | Rejilla | Control (H1) |
| 4 Confirmar | Iván | Escribe Los Yesos | UI-04 | Oficio, no rider |
| 5 Hora ≠ concierto | Iván | Ve el código; lee el disclaimer | /ok/:code | Límite claro (H2) |
| 6 Entrar a turno | Lola | Login JWT; aterriza en horario | /login → /turno | Oficio, «quién ocupa» |
| 7 Lectura | Lola | Lee Marta Chen en Sala 1 16–18; ve Combo 18–20 Los Yesos tras el POST | /turno | Control (H3) |
| 8 Llaves (fuera) | Lola | Da las llaves en ventanilla; cobra fuera | Backstage | El producto no finge el candado |
| 9 No taquilla | Lola | No hay aforo ni entrada | Ausencia de UI | Integridad |
Momentos de verdad
- 3 salas + 3 datos en el primer viewport — si hay que «descubrir la marca», se rompe H-KIOSK / AP-21. [HIPÓTESIS]
- Sin cuenta — si aparece «regístrate», S2 / H3 fallan.
- Success dice que hora no es concierto — evita la mentira de la entrada.
- Cero CTA de entradas y cero 112 como envío — si aparece «Comprar entrada» como primary, el microcopy falla.
- Horario, no kanban — S-MIN / F-BOOK staff. [HIPÓTESIS]
- Bloque cogido no se recoge — 409 visible. [DECISIÓN]
7. Service blueprint (resumen)
| Capa | Elementos |
|---|---|
| Frontstage BANDA | Kiosk, salas, rejilla, confirmar, ticket. Sin turno |
| Frontstage CONSERJE | Login, horario de hoy |
| Backstage | Llaves físicas, cobro en ventanilla, WhatsApp de la nave, Conciergo (fuera), 112 (fuera) |
| Sistemas | Nest API :3021, Neon divine-haze-05909195, JWT, Angular |
| Soportes | Seed 1 CONSERJE + 3 salas + 8 horas + fotos, Paper, docs |
| Fallos | 0 salas; 0 horas libres; 409 slot; 401 en turno; red caída → UI error |
Fallos de servicio y respuesta de diseño
| Fallo | Evidencia de UI | Recuperación |
|---|---|---|
| 0 salas | UI-08 Empty kiosk | «Aún no hay salas.» |
| 0 horas libres en una sala | UI-08 Empty slots | «Hoy no queda hora en esta sala.» + volver |
| Slot cogido al POST | 409 | «Esa hora ya está cogida.» + rejilla refresca |
| API caída | UI-09 Error | Reintentar |
| Latencia kiosk | Loading (doc 16) | Skeleton 3 salas |
| Form inválido | Inline field | No navegar a /ok |
| Código inexistente en ticket | Ticket genérico | Muestra el código de la URL + copy; no inventa la hora |
Sin token en /turno | Redirect | /login |
| POST spam | 429 Should | Rate limit L+1 |
8. Matriz hallazgo → requisito → feature
| Hallazgo | Tipo | Requisito | Feature v1 |
|---|---|---|---|
| Coge hora en el pasillo, funda en el suelo | [SUPUESTO] S2 | Kiosk 390/1440, targets ≥44, sin cuenta | H-KIOSK · UI-01/02 |
| Pregunta «¿está libre la 2?» por WhatsApp | [HIPÓTESIS] H1 | 3 salas + rejilla de hoy | GET rooms + slots |
| Hora se lee como concierto | [HIPÓTESIS] H2 | Copy irrenunciable | UI-05 Success |
| Sala se lee como escenario | [DECISIÓN] | Copy irrenunciable | Kiosk + ticket |
| El canal se lee como 112 | [DECISIÓN] | Copy de límite | Pie kiosk |
| El tablero se lee como kanban | [DECISIÓN] | Horario, no columnas | UI-07 Turno |
| Pago / rider el día 1 | [DECISIÓN] S4 | Cero pasarela, cero backline extra | Confirmar solo nombre |
| Banda no necesita login | [HIPÓTESIS] H3 | Público POST + JWT solo turno | Guards |
| L2 compacto, no PMS | [DECISIÓN] | 3 salas, 5 bloques, hoy | F-BOOK |
| Nombres ajenos en el pasillo | [DECISIÓN] D9 | Kiosk: free/taken | GET :slug sin bandName |
9. Preguntas abiertas (no bloquean v1)
| ID | Pregunta | Cómo se resolvería después |
|---|---|---|
| Q1 | ¿Iván recarga /ok/:code y pierde sala/hora? | [DECISIÓN v1] el ticket vive del POST + URL. Could: ticket público mínimo { code, slot, roomName } |
| Q2 | ¿Lola cancela una hora? | Fuera v1. Could L+1: cancel CONSERJE, no self-service de banda |
| Q3 | ¿Bloques ya pasados se ocultan? | Demo no los greyea para que el smoke siempre funcione. L+1: grey. [DECISIÓN] |
| Q4 | ¿Paseo de Yeserías está en Carabanchel? | Atrezzo de catálogo; no se afirma catastro. [SUPUESTO de catálogo] |
| Q5 | ¿Las fotos de sala son de una nave real? | Assets de case; no se presentan como local existente. [SUPUESTO de catálogo] |
| Q6 | ¿El correo @temple.nave existe? | No. Credencial demo. |
| Q7 | ¿Se puede coger mañana? | No en v1. Solo hoy. [DECISIÓN] D13 |
10. Plan de research futuro (si hubiera campo real)
| Método | Muestra orientativa | Pregunta |
|---|---|---|
| Test de usabilidad kiosk 390 / 1440 | 5–6 músicos 20–40 | ¿Cogen un bloque en < 60 s sin cuenta? |
| Shadowing de turno | 1 conserje de nave | ¿El horario sustituye el WhatsApp? |
| Revisión de expectativa concierto | Comentarios «¿entrada?» | Validar H2 |
| Recorrido con teclado + letra grande | 5 sesiones | ¿Los targets de 44px bastan con funda en el suelo? |
Estos métodos no se han ejecutado. No se reportan hallazgos como si lo hubieran sido.
11. Síntesis
TEMPLE se diseña como quiosco de horas que se coge y se mira en un horario, no como taquilla, no como escenario y no como chat.
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
03 — Arquitectura de información — TEMPLE
1. Principios de IA
| Principio | Aplicación |
|---|---|
| Kiosk first | La home son las 3 salas. No hay landing de marca por delante |
| Público / turno | El músico coge hora sin cuenta; Lola entra con JWT |
| Sala → hora → ticket | Profundidad 2 desde el kiosk hasta el código |
| Turno = horario | Filas de bloques, columnas de salas; no kanban |
| Lenguaje de dominio | Sala, hora, ticket, turno — no «entrada», «lead», «expediente», «parte» |
| Hora no es concierto | El ticket no tiene aforo ni puerta |
| Sala no es escenario | El cuarto tiene moqueta, no palco |
| Chrome mínimo | S-MIN: casi sin nav; el quiosco es una acción |
2. Sitemap
/ Kiosk público (3 salas) H-KIOSK
/sala/:slug Rejilla de horas + confirmar F-BOOK · público
/ok/:code Ticket post-hora público
/login Login JWT CONSERJE público
/turno Horario de ocupación de hoy auth
/** → redirect / (si no hay token) o /turno
Árbol por audiencia
| Audiencia | Nodos relevantes |
|---|---|
| BANDA / BATERÍA | Kiosk → Sala → Ok. No ven turno |
| CONSERJE | Login → Turno · (puede leer el kiosk) |
| Taquilla / 112 | Ninguno como rol de sistema |
[COMPROBADO] Cinco rutas del encargo L2. No se inventan /entradas, /concierto, /112, /mesa, /chat, /hoy, /fichas.
Confirmación (UI-04) no es ruta extra: es estado de /sala/:slug con slot seleccionado. [DECISIÓN]
3. Navegación
Kiosk público (S-MIN · sin top-nav de marketing)
| Elemento | Destino | Notas |
|---|---|---|
| Wordmark TEMPLE | / | No es hero; es sello del quiosco |
| Eslogan | — | «La hora, no el concierto.» |
| Card sala | /sala/:slug | 3 tiles enormes |
| Pie / link Turno | /login o /turno si hay token | Secundario, mute, no CTA de marca |
[DECISIÓN] El kiosk no tiene tabs, no tiene hamburger, no tiene «Conciertos / Entradas / Agenda». Un link «Turno» discreto basta para Lola.
Chrome de turno (S-MIN autenticado)
| Slot | Destino | Visibilidad | Notas |
|---|---|---|---|
| Wordmark | /turno | Auth | No lleva al kiosk |
| Hoy | — | Auth | Fecha de ocupación, no selector de mes |
| Salir | limpia token → /login | Auth | Cabecera, no rail |
[DECISIÓN] No hay rail S-SIDE (eso fue PREGÓN). No hay bottom tabs (MATIZ). No hay masthead (MARGEN). El turno es una tabla-horario a pantalla.
Desktop ≥960px: cabecera 64px + matriz 5 filas × 3 columnas.
Mobile ~390px: la matriz se apila por sala (UI-11 slots mobile es del kiosk; el turno en 390 es lista por sala). [DECISIÓN] En 390 no hay hamburger ni tres columnas aplastadas de kanban.
Header contextual
| Superficie | Izquierda | Centro | Derecha |
|---|---|---|---|
Kiosk / | Wordmark | — | Turno (ghost) |
Sala /sala/:slug | ← Salas | Nombre de sala | — |
| Ok | Wordmark | — | Coger otra |
| Login | Wordmark | — | — |
| Turno | Wordmark | Hoy | Lola · Salir |
[DECISIÓN] El wordmark en autenticado lleva a /turno (no al kiosk), para no mezclar oficios. El wordmark en público lleva a /.
Login (público; solo oficio)
| Elemento | Destino | Notas |
|---|---|---|
| Email / password / Entrar | POST login → /turno | JWT |
| Error | no navega | Inline |
| Pie | no «crear cuenta de banda» | No hay signup |
| Volver al kiosk | / | Ghost |
[DECISIÓN] No hay /registro. No hay «Soy banda». No hay taquilla.
4. Inventario de contenido
| Pantalla | Contenidos |
|---|---|
Kiosk / | Wordmark, eslogan, 3 salas (foto, lead, 3 datos), disclaimers, empty, loading, error |
Sala /sala/:slug | Foto, nombre, kind, m², rejilla 5 bloques, estado confirmar |
| Confirmar | Slot elegido, nombre de banda, «se paga en ventanilla», Coger hora |
Success /ok/:code | Código, sala, bloque, «hora ≠ concierto», «no vende entradas», CTA coger otra |
Login /login | Wordmark, eslogan, email, password, submit, error, volver al kiosk |
Turno /turno | Cabecera S-MIN, matriz horario (sala × bloque × banda), empty, loading, error |
| Empty | 0 salas · 0 horas libres |
| Error | Red · 409 slot cogido |
| Loading | Skeletons de 3 salas / rejilla / matriz |
| Kiosk mobile | 3 salas apiladas · rejilla 390 |
5. Taxonomía
Role
| Status API | Label UI | Semántica |
|---|---|---|
CONSERJE | Conserje | Único rol autenticado v1 |
[DECISIÓN] No hay BANDA / TAQUILLA / OPERADOR / COLORISTA.
BookingStatus
| Status API | Label UI | Semántica |
|---|---|---|
CONFIRMED | Cogida | Hora tomada; no es entrada ni concierto |
v1 no tiene CANCELLED como Must. L+1: cancel CONSERJE. [DECISIÓN]
Slot
| API | Label UI |
|---|---|
10-12 | 10–12 |
12-14 | 12–14 |
16-18 | 16–18 |
18-20 | 18–20 |
20-22 | 20–22 |
Orden de filas: 10–12 → 12–14 → 16–18 → 18–20 → 20–22.
No existe 14-16. [DECISIÓN] D13
Kind / Room
| API slug | Kind | Label UI |
|---|---|---|
bateria | bateria | Sala 1 Batería |
combo | combo | Sala 2 Combo |
seca | seca | Sala 3 Seca |
SlotStatus (kiosk)
| API | Label UI | Semántica |
|---|---|---|
free | Libre | Se puede coger |
taken | Cogida | No se puede coger; sin nombre de banda |
Salas (líneas seed)
| slug | Nombre | Lead | 3 datos |
|---|---|---|---|
bateria | Sala 1 Batería | Kit dentro | Batería · 12 m² · 2 de 5 libres |
combo | Sala 2 Combo | Amp + PA chico | Combo · 18 m² · 2 de 5 libres |
seca | Sala 3 Seca | Sin batería | Seca · 10 m² · 3 de 5 libres |
[COMPROBADO] Tres salas del encargo. [DECISIÓN]
Horas (líneas seed)
| code | slug | slot | bandName |
|---|---|---|---|
TM-2101 | bateria | 10-12 | Cuarto Aire |
TM-2102 | combo | 10-12 | Tres Cables |
TM-2103 | seca | 12-14 | Papel Fumado |
TM-2104 | bateria | 16-18 | Marta Chen |
TM-2105 | combo | 16-18 | Las Cajas |
TM-2106 | seca | 18-20 | Eco Bajo |
TM-2107 | bateria | 20-22 | Tres Cables |
TM-2108 | combo | 12-14 | Cuarto Aire |
[COMPROBADO] Ocho horas, 8 cogidas / 7 libres, del encargo de seed. Nombres de banda extra = catálogo. [SUPUESTO de catálogo]
6. Modelo mental vs UI
| Modelo mental | Representación |
|---|---|
| «¿Está libre la 2?» | Kiosk / + card Sala 2 |
| «La quiero a las seis» | Rejilla /sala/combo · 18–20 |
| «Somos Los Yesos» | Confirmar · bandName |
| «¿Me han dado entrada?» | No. Copy: hora cogida ≠ concierto |
| «¿Tocamos en público?» | No. Copy: ensayar no es actuar |
| «¿Quién ocupa hoy?» | Turno, matriz horario |
| «¿En qué columna está?» | No hay columnas de estado |
| «¿Dónde pago?» | Copy: ventanilla. Cero pasarela |
| «¿Es el 112?» | No hay UI. Copy: TEMPLE no es 112 |
| «Salgo del turno» | Cabecera → Salir |
7. Query string y estado
| Ruta | Query / state | Uso |
|---|---|---|
/login | ?next=/turno | Redirect post-login sanitizado |
/sala/:slug | state slot o ?slot=18-20 (Should) | Abre confirmar |
| Resto | — | Sin ?day= Must · sin ?q= |
[DECISIÓN] Sin calendario. Solo hoy. L+1: ?day=.
El confirmar no persiste borrador en sessionStorage como Must. Si se sale sin coger, se pierde el nombre. Could L+1: draft local.
/ok/:code no hace GET JWT. El código vive en la URL. Detalle de sala/hora: state del POST si existe. [DECISIÓN] D9 (nombres ajenos no se enumeran por código público hidratado). Could L+1: GET público mínimo { code, roomName, slot } sin listar el resto.
8. Rutas API alineadas a IA
| UI | API |
|---|---|
| Kiosk / salas | GET /api/rooms público |
| Rejilla | GET /api/rooms/:slug público |
| Coger hora | POST /api/bookings público |
| Login | POST /api/auth/login |
| Turno | GET /api/turno JWT |
| Salud | GET /api/health · service: "temple-api" |
[COMPROBADO] Contrato del encargo. No se documentan entradas, 112 ni PATCH de kanban como Must.
GET /api/me es Could (el login ya devuelve user). Turno puede pintar «Lola Rivas» desde temple_user en storage.
9. Decisiones de IA descartadas
| Idea | Por qué no en L2 v1 |
|---|---|
/entradas aforo | Rompe H2; eso es Conciergo |
| Área «mis horas» con cuenta | Cuenta de facto; contradice H3 |
| Nombres de otras bandas en el kiosk | Privacidad de pasillo; D9 |
| Search como home | H-SEARCH de otros días |
| Chat de incidencias | H-CHAT de PREGÓN |
| Kanban Recibido / En curso | F-KAN de PREGÓN |
| Hoy bento de sillas | H-BENTO de MATIZ |
| Wizard de 3 pasos | ZAGUÁN |
| Lookbook editorial | H-GALLERY de MARGEN |
/concierto / /112 | Rompe microcopy |
| Bottom tabs Kiosk · Turno · Cuenta | Mezclaría oficios; el músico no tiene turno |
| Top-nav Conciertos / Agenda / Tienda | Marketing de sala; contradice el brief |
| Calendario semanal | D13: solo hoy |
04-user-flows.md
04 — Flujos de usuario — TEMPLE
Convenciones
- Actor: Guest (banda/batería anónima) | CONSERJE
- Éxito: resultado observable
- Errores: UI + código HTTP cuando aplica
- Flujo canónico músico: F-BOOK (kiosk → sala → slot → confirmar → ok)
- Flujo canónico oficio: F-TURNO (login → horario de hoy)
- Taquilla / 112: no tienen flujo de sistema
F0 — Entrada pública (Guest)
/ → GET /api/rooms → 3 salas enormes
/sala/:slug → GET /api/rooms/:slug → rejilla + confirmar
/ok/:code → ticket (sin GET JWT)
/login → si hay token válido → /turno (o next)
/turno sin token → /login?next=/turno
| Paso | Acción | Sistema |
|---|---|---|
| 1 | Aterriza en el kiosk | Router público |
| 2 | Lee 3 salas (lead + 3 datos) | UI-01 / UI-02 |
| 3 | No encuentra «crear cuenta» ni «comprar entrada» | IA |
Éxito: cara pública = quiosco de salas.
AC: no hay landing, hero 2-col ni taquilla. Kiosk-first.
F1 — Ver salas (Guest) · H-KIOSK
/ → GET /api/rooms
→ 3 salas | empty | error | skeleton
| Paso | Acción | Sistema |
|---|---|---|
| 1 | Lee Sala 1 Batería, Sala 2 Combo, Sala 3 Seca | rooms |
| 2 | Lee 3 datos por sala (kind, m², libres de 5) | UI |
| 3 | Toca una sala | Router /sala/:slug |
Éxito: 3 salas reales en el fold, o empty accionable.
AC: cada sala muestra nombre + lead + 3 datos + foto. Cero botones Entradas / Concierto.
Guión Iván (demo): toca Sala 2 Combo. [SUPUESTO de catálogo] alineado al seed de doc 05.
| Caso | Comportamiento |
|---|---|
| 0 salas | UI-08: «Aún no hay salas.» |
| Red / 5xx | UI-09 + Reintentar (repite GET) |
| Primera carga | Skeleton 3 tiles (doc 16) |
F2 — Ver horas (Guest) · F-BOOK
/sala/:slug → GET /api/rooms/:slug
→ 5 bloques free|taken | empty | error | skeleton
| Paso | Acción | Sistema |
|---|---|---|
| 1 | Lee nombre de sala y foto | Room |
| 2 | Lee 10–12 … 20–22 | slots |
| 3 | Toca un bloque free | Abre confirmar (UI-04) |
| 4 | Toca un bloque taken | No abre confirmar; estado cogida |
Éxito: rejilla de hoy; taken sin nombre de banda.
AC: 5 bloques. Libre = CTA. Cogida = no clicable (o clic = mensaje, no POST).
Guión Iván: Sala 2 · 18–20 libre · 10–12 y 12–14 y 16–18 cogidas. [SUPUESTO de catálogo]
| Caso | Comportamiento |
|---|---|
| 0 libres | UI-08: «Hoy no queda hora en esta sala.» + ← Salas |
| Red / 5xx | UI-09 + Reintentar |
| Primera carga | Skeleton rejilla (doc 16) |
| Slug inexistente | 404 UI + volver al kiosk |
F3 — Confirmar y coger hora (Guest) · F-BOOK
/sala/:slug (slot seleccionado)
→ bandName
→ POST /api/bookings { roomSlug, slot, bandName }
→ 201 Booking { code, status: CONFIRMED, ... }
→ /ok/:code
| Campo | Validación cliente (mín.) | API |
|---|---|---|
| bandName | required, min 2, max 80 | @MinLength(2) |
| roomSlug | de la ruta | bateria | combo | seca |
| slot | seleccionado, enum | 10-12 | 12-14 | 16-18 | 18-20 | 20-22 |
| day | no en POST; siempre hoy | servidor fuerza today Europe/Madrid |
| status | no en POST; siempre CONFIRMED | servidor fuerza CONFIRMED |
| code | no en POST | servidor asigna TM-XXXX |
Éxito: registro status=CONFIRMED + pantalla ticket.
No hay «Entrada» ni «Escenario» ni pago en v1.
JSON camelCase: bandName, roomSlug. [DECISIÓN]
| Gestos | Resultado |
|---|---|
| Slot libre | Selecciona; abre confirmar |
| Nombre | text |
| Coger hora | POST; pending en botón |
| Inválido | Inline; no POST |
| Doble submit | Botón disabled mientras pending |
| Cancelar confirmar | Vuelve a rejilla; no POST |
Errores
| Caso | Comportamiento |
|---|---|
| Validación DTO | 400 + mensaje de campo |
| Slot ya cogido | 409 SLOT_TAKEN · rejilla refresca · no navegar a /ok |
| Red caída | Error de red en form; no navegar a /ok/… |
| 429 | Should: «Espera un momento para coger otra.» |
| Slot / slug fuera de enum | 400 |
[DECISIÓN] Crear siempre como CONFIRMED. Pago fuera (ventanilla). Unique (room_id, day, slot).
[COMPROBADO] Entidad Booking según encargo (code, sala, slot, banda).
F4 — Ticket (Guest)
/ok/:code → muestra código de la URL
→ si hay router state del POST: sala / slot / banda
→ “Hora cogida ≠ concierto. TEMPLE no vende entradas.”
→ “Sala ≠ escenario. Ensayar no es actuar.”
→ CTA coger otra → /
| Paso | Acción | Sistema |
|---|---|---|
| 1 | Lee código y copy | UI-05 |
| 2 | No abre el turno | Guard |
| 3 | Puede coger otra | Router |
AC: el disclaimer es visible sin scroll en desktop.
No hace GET /api/turno ni lista otras horas. Si se recarga, queda el código + copy; no se inventa la banda. [DECISIÓN] D9.
Código con formato inválido (no TM- + 4 dígitos): mismo ticket genérico; no 404 de producto público.
F5 — Login JWT (CONSERJE)
/login → POST /api/auth/login { email, password }
→ 200 { accessToken, user } → localStorage → /turno (o ?next sanitizado)
→ 401 → mensaje error en form
| Campo | Validación cliente | API |
|---|---|---|
| required, email | @IsEmail() | |
| password | required, min 6 | @MinLength(6) |
Éxito: token guardado; user role=CONSERJE, nombre Lola Rivas.
Credencial demo: lola@temple.nave / password123.
| Caso | Comportamiento |
|---|---|
| Credenciales inválidas | 401 + mensaje |
| Red caída | Error de red en UI |
| Token caducado en turno | 401 en GET → re-login |
next externo / // | Ignorado; va a /turno |
| Banda en login | No hay signup; link «Volver al kiosk» |
[COMPROBADO] Credencial del encargo.
F6 — Turno horario (CONSERJE) · F-TURNO
/turno (token)
→ GET /api/turno
→ matriz 5×3 (bandName | libre)
→ tablero | empty | error | skeleton
| Paso | Acción | Sistema |
|---|---|---|
| 1 | Lee filas 10–12 … 20–22 | slots |
| 2 | Lee columnas Sala 1 / 2 / 3 | rooms |
| 3 | Lee banda o «Libre» en cada celda | Booking | null |
Éxito: 8 cogidas / 7 libres en el seed, o empty.
AC celdas: cada una muestra banda o Libre. Cero botones Entradas / 112 / Kanban. Cero drag-and-drop Must.
Guión Lola (demo): Sala 1 16–18 Marta Chen · Sala 2 18–20 Libre (hasta el POST de Iván) · tras el POST, Los Yesos. [SUPUESTO de catálogo]
| Caso | Comportamiento |
|---|---|
| 0 horas en el día | UI-08: «Hoy no hay horas apuntadas.» (salas siguen existiendo) |
| Red / 5xx | UI-09 + Reintentar |
| Primera carga | Skeleton matriz (doc 16) |
| Sin token | Redirect /login |
| 401 mid-session | Redirect /login |
[DECISIÓN] GET /api/turno es el Must de producto. No hay PATCH de status. Lola mira, no mueve columnas. Could L+1: cancel.
F7 — Kiosk / slots mobile (Guest) · UI-02 / UI-11
/ ~390
→ 3 salas apiladas (mismas 3, no un carousel de marketing)
/sala/:slug ~390
→ rejilla 1 col o 2 col de bloques
→ confirmar hoja inferior
Misma API que F1–F3. No se aplastan 3 columnas de kanban. [DECISIÓN]
F8 — Logout (CONSERJE)
Turno → Salir → limpia localStorage → /login
| Caso | Comportamiento |
|---|---|
| Salir | Borra temple_token + temple_user |
Tras salir, /turno | Redirect login |
Tras salir, / | Kiosk público intacto |
No hay pantalla /cuenta Must. [DECISIÓN]
F9 — Health (ops)
GET /api/health → 200 { ok: true, service: "temple-api" }
Sin auth. No es una pantalla. Smoke de arranque.
[COMPROBADO] El contrato de esta suite es temple-api :3021.
Matriz de errores global
| Código | Cuándo | UI |
|---|---|---|
| 400 | DTO inválido | Mensaje campo / genérico |
| 401 | Sin/mal token en turno | Re-login |
| 404 | slug no existe | Mensaje + volver al kiosk |
| 409 | Slot cogido | «Esa hora ya está cogida.» + refresh rejilla |
| 429 | Rate limit POST | Espera |
| 5xx / network | API caída | Error + retry |
Flujos fuera de alcance v1
- Registro / recuperación de password de CONSERJE
- Cuenta de banda / «mis horas» / push
- Entradas / aforo / Conciergo
- 112 / derivación operativa
- Pago en kiosk
- Calendario semanal
- Cancelación / no-show
- Chat
- Kanban
- Rider / backline extra
- Multi-conserje / multi-nave
05-data-model.md
05 — Modelo de datos — TEMPLE
1. Visión general
Dominio L2 de quiosco de horas + turno autenticado:
| Entidad | Tabla SQL | Propósito |
|---|---|---|
| User | users | Identidad de oficio (rol CONSERJE) |
| Session | sessions | Sesión JWT / token persistido (Should) |
| Room | rooms | Sala de ensayo (batería / combo / seca) |
| Booking | bookings | Hora cogida (código TM-XXXX) |
Base: PostgreSQL (Neon project divine-haze-05909195) · IDs: cuid() o texto estable (usr_lola, rm_1, TM-2101).
[DECISIÓN] ensureSchema o Prisma son válidos si el contrato de tablas se cumple; el brief de stack no exige Prisma.
Contrato de producto: rooms + bookings + JWT CONSERJE. No bandos / reports / clients / formulas.
2. Enums (aplicación; persistidos como TEXT + check)
Role
| Valor | Descripción |
|---|---|
CONSERJE | Conserje del turno; único rol autenticado v1 |
BookingStatus
| Valor | Descripción |
|---|---|
CONFIRMED | Hora cogida; no implica concierto ni entrada |
RoomKind
bateria | combo | seca
Slot
10-12 | 12-14 | 16-18 | 18-20 | 20-22
3. Diagrama ER (texto)
users
id, email, password_hash, name, role(CONSERJE)
nave_name
created_at, updated_at
1 ──< sessions
sessions
id, user_id → users
token_hash, expires_at
created_at
rooms
id
slug (unique)
name, kind, size_m2, lead
cover -- filename
sort_order
created_at, updated_at
1 ──< bookings
bookings
id
code (unique, TM-XXXX)
room_id → rooms
day (DATE)
slot (10-12|…)
band_name
status (CONFIRMED)
created_at, updated_at
UNIQUE (room_id, day, slot)
v1: una sola CONSERJE opera sobre el conjunto global.
No hay FK de banda-usuaria: la banda no se loguea.
bookingsno apunta ausers: la hora es anónima de cuenta.
4. Tablas
users
| Campo | Tipo | Constraints |
|---|---|---|
| id | TEXT | PK |
| TEXT | UNIQUE NOT NULL | |
| password_hash | TEXT | NOT NULL (bcrypt) |
| name | TEXT | NOT NULL |
| role | TEXT | NOT NULL DEFAULT 'CONSERJE' |
| nave_name | TEXT | NOT NULL DEFAULT 'TEMPLE · Carabanchel' |
| created_at | TIMESTAMPTZ | DEFAULT now() |
| updated_at | TIMESTAMPTZ | DEFAULT now() |
sessions
| Campo | Tipo | Constraints |
|---|---|---|
| id | TEXT | PK |
| user_id | TEXT | NOT NULL FK → users(id) ON DELETE CASCADE |
| token_hash | TEXT | NOT NULL |
| expires_at | TIMESTAMPTZ | NOT NULL |
| created_at | TIMESTAMPTZ | DEFAULT now() |
[DECISIÓN] El JWT viaja en Authorization: Bearer. sessions permite invalidar (logout) sin esperar expiración. Si el slice usa JWT stateless, documentar el hueco; D-P1-05 se cumple igual con guard en turno.
rooms
| Campo | Tipo | Constraints |
|---|---|---|
| id | TEXT | PK |
| slug | TEXT | UNIQUE NOT NULL · bateria | combo | seca |
| name | TEXT | NOT NULL |
| kind | TEXT | NOT NULL CHECK IN (bateria,combo,seca) |
| size_m2 | INTEGER | NOT NULL |
| lead | TEXT | NOT NULL |
| cover | TEXT | NOT NULL · filename (bateria.jpg) |
| sort_order | INTEGER | NOT NULL DEFAULT 1 |
| created_at / updated_at | TIMESTAMPTZ |
[DECISIÓN] GET público lista sort_order asc. L+1: salas inactivas.
bookings
| Campo | Tipo | Constraints |
|---|---|---|
| id | TEXT | PK |
| code | TEXT | UNIQUE NOT NULL · ^TM-\d{4}$ |
| room_id | TEXT | NOT NULL FK → rooms(id) |
| day | DATE | NOT NULL |
| slot | TEXT | NOT NULL CHECK IN (10-12,12-14,16-18,18-20,20-22) |
| band_name | TEXT | NOT NULL |
| status | TEXT | NOT NULL DEFAULT 'CONFIRMED' |
| created_at / updated_at | TIMESTAMPTZ |
UNIQUE (room_id, day, slot).
[DECISIÓN] SQL snake_case (band_name, room_id); JSON camelCase (bandName, roomId).
5. Reglas de integridad y negocio
| Regla | Implementación |
|---|---|
| Lectura de salas | Pública |
| Lectura de rejilla | Pública · slots free / taken sin bandName |
| Alta de hora | Pública · status forzado CONFIRMED · code asignado · day = hoy Europe/Madrid |
| Lectura de turno | JWT CONSERJE → 401 sin token · sí bandName |
| Login / health | Públicos |
| Password | Nunca en claro; solo password_hash |
| Orden salas | sort_order asc |
| Orden bloques | 10-12, 12-14, 16-18, 18-20, 20-22 |
| POST Booking | no emite entrada; no cobra; no llama al 112 |
| Público nunca lista bookings | no hay GET público de horas ajenas |
| Cover allowlist | filenames seed |
| Código | secuencial TM- + 4 dígitos; seed hasta 2108 → siguiente 2109 |
| Choque de hora | UNIQUE → 409 SLOT_TAKEN |
| Solo hoy | POST ignora day del cliente |
6. Contratos API (resumen)
JSON camelCase hacia el web. [DECISIÓN]
GET /api/health
Response 200: { "ok": true, "service": "temple-api" }
[COMPROBADO] Contrato del encargo: temple-api.
GET /api/rooms
Público.
Response 200: Room[]
[
{
"id": "rm_1",
"slug": "bateria",
"name": "Sala 1 Batería",
"kind": "bateria",
"sizeM2": 12,
"lead": "Kit dentro",
"cover": "bateria.jpg",
"sortOrder": 1,
"freeToday": 2,
"slotsToday": 5
}
]
Si 0: [] + empty UI-08.
freeToday / slotsToday se calculan para hoy Europe/Madrid. [DECISIÓN]
GET /api/rooms/:slug
Público.
Response 200
{
"id": "rm_2",
"slug": "combo",
"name": "Sala 2 Combo",
"kind": "combo",
"sizeM2": 18,
"lead": "Amp + PA chico",
"cover": "combo.jpg",
"day": "2026-08-21",
"slots": [
{ "slot": "10-12", "status": "taken" },
{ "slot": "12-14", "status": "taken" },
{ "slot": "16-18", "status": "taken" },
{ "slot": "18-20", "status": "free" },
{ "slot": "20-22", "status": "free" }
]
}
Sin bandName en slots públicos. Slug inexistente → 404.
POST /api/bookings
Público.
Body
| Campo | Tipo | Req |
|---|---|---|
| roomSlug | bateria | combo | seca | sí |
| slot | 10-12 | 12-14 | 16-18 | 18-20 | 20-22 | sí |
| bandName | string 2–80 | sí |
Response 201
{
"code": "TM-2109",
"roomSlug": "combo",
"roomName": "Sala 2 Combo",
"slot": "18-20",
"bandName": "Los Yesos",
"day": "2026-08-21",
"status": "CONFIRMED",
"createdAt": "2026-08-21T16:12:00.000Z"
}
DTO inválido → 400. Slot cogido → 409 { "error": "SLOT_TAKEN" }. No JWT.
POST /api/auth/login
Body: { email, password }
Response 200: { accessToken, user: { id, email, name, role, naveName } }
401 credenciales inválidas. Response sin hash.
GET /api/turno (JWT)
Response 200
{
"day": "2026-08-21",
"naveName": "TEMPLE · Carabanchel",
"slots": ["10-12", "12-14", "16-18", "18-20", "20-22"],
"rooms": [
{
"slug": "bateria",
"name": "Sala 1 Batería",
"cells": [
{ "slot": "10-12", "status": "taken", "bandName": "Cuarto Aire", "code": "TM-2101" },
{ "slot": "12-14", "status": "free", "bandName": null, "code": null },
{ "slot": "16-18", "status": "taken", "bandName": "Marta Chen", "code": "TM-2104" },
{ "slot": "18-20", "status": "free", "bandName": null, "code": null },
{ "slot": "20-22", "status": "taken", "bandName": "Tres Cables", "code": "TM-2107" }
]
}
]
}
Sin token → 401.
GET /api/me (Could)
JWT. { id, email, name, role, naveName }. El login ya trae user; no es Must del encargo.
7. Seed de referencia (2026-08-21)
CONSERJE
| Nombre | Password | Nave | |
|---|---|---|---|
| Lola Rivas | lola@temple.nave | password123 | TEMPLE · Carabanchel |
[COMPROBADO] Credencial del encargo. Nombre de pila es constructo de diseño.
Rooms (3)
| id | slug | name | kind | size_m2 | lead | cover | sort |
|---|---|---|---|---|---|---|---|
rm_1 | bateria | Sala 1 Batería | bateria | 12 | Kit dentro | bateria.jpg | 1 |
rm_2 | combo | Sala 2 Combo | combo | 18 | Amp + PA chico | combo.jpg | 2 |
rm_3 | seca | Sala 3 Seca | seca | 10 | Sin batería | seca.jpg | 3 |
Fotos y m² son catálogo demo, no un inventario de nave real. [SUPUESTO de catálogo]
Bookings (8)
Bandas, horas y fotos son catálogo demo, no reservas reales. [SUPUESTO de catálogo]
day seed = hoy al boot (Europe/Madrid), o fecha fija 2026-08-21 si el slice prefiere determinismo. [DECISIÓN] Preferir hoy relativo para que el turno nunca parezca de ayer en demo.
| code | slug | slot | bandName |
|---|---|---|---|
| TM-2101 | bateria | 10-12 | Cuarto Aire |
| TM-2102 | combo | 10-12 | Tres Cables |
| TM-2103 | seca | 12-14 | Papel Fumado |
| TM-2104 | bateria | 16-18 | Marta Chen |
| TM-2105 | combo | 16-18 | Las Cajas |
| TM-2106 | seca | 18-20 | Eco Bajo |
| TM-2107 | bateria | 20-22 | Tres Cables |
| TM-2108 | combo | 12-14 | Cuarto Aire |
Conteos: 8 CONFIRMED · 7 libres.
Libres de guión: Sala 1 12-14 y 18-20 · Sala 2 18-20 y 20-22 · Sala 3 10-12, 16-18 y 20-22.
Iván / Los Yesos no está en el seed: el POST demo coge Sala 2 18-20 → TM-2109.
Paseo de Yeserías / Carabanchel es atrezzo de mercado. No se afirma catastro ni local existente. [SUPUESTO de catálogo]
8. Evolución posible (no implementada)
| Cambio | Nivel |
|---|---|
Ticket público mínimo { code, roomName, slot } | L+1 |
| Cancel CONSERJE | L+1 |
| Grey de bloques pasados | L+1 |
| Segundo CONSERJE | L+1 / L3 |
Calendario ?day= | L+1 / L3 |
| Soft delete + audit log | L3 |
| Pago / taquilla / entradas | Fuera (H2 / S4) |
| Cuenta de banda | Fuera (H3) |
| 112 / kanban / chat | Fuera (microcopy / terna) |
06-tech-stack.md
06 — Stack tecnológico — TEMPLE
1. Visión
| Capa | Tecnología | Notas |
|---|---|---|
| Frontend | Angular standalone + signals | Puerto 4200 · web kiosk-first |
| Estilos | Tailwind CSS | Tokens vehicle dashboard (ink, panel, cream, amber, mute, jewel) |
| Backend | NestJS TypeScript | Puerto 3021, prefijo /api |
| Persistencia | PostgreSQL (ensureSchema o Prisma) | Tablas users, rooms, bookings (+ sessions Should) |
| DB | Neon PostgreSQL | project divine-haze-05909195 |
| Auth | JWT | Rol CONSERJE (turno); kiosk y POST bookings públicos |
| Diseño | Paper | 01M0HJ2Z7NJSYC0FDMWYSSQBG3 |
| Repo | /Users/cristian/orca/temple-app/ | GitHub Criscode2022/temple-app |
Stack fijo del cron (D-P0-03). No React/Next/Firebase.
[COMPROBADO] Puerto 3021, Neon, Paper y repo constan en el encargo.
El código se escribe en paralelo a esta suite. Este doc es el contrato, no un inventario de leftover.
2. Estructura
temple-app/
├── apps/api/ # Nest (paquete independiente)
├── apps/web/ # Angular + Tailwind (paquete independiente)
└── package.json # scripts api / start · apps independientes
D-P1-03: npm --prefix o pnpm --filter. Prohibido npm workspaces que rompen Angular (AP-06).
Scripts raíz esperados:
| Script | Acción |
|---|---|
| api | Arranca Nest en :3021 |
| start / web | Arranca Angular en :4200 |
3. API pública vs JWT
| Método | Ruta | Auth |
|---|---|---|
| GET | /api/health | Público · { ok: true, service: "temple-api" } |
| GET | /api/rooms | Público |
| GET | /api/rooms/:slug | Público |
| POST | /api/bookings | Público |
| POST | /api/auth/login | Público |
| GET | /api/turno | JWT CONSERJE |
CORS: origen http://localhost:4200 en local.
[COMPROBADO] Superficie API del encargo. No se añaden Must extra (/me, /entradas, /reports).
4. Justificación
| Elección | Razón |
|---|---|
| Angular + Nest | Alineación con la serie daily y el handoff del estudio |
| Neon serverless | Volumen bajo (S1: 12–20 h/día; demo 3 salas × 5 bloques); no cola Redis |
| JWT CONSERJE | D-P1-05: turno interno cerrado; el kiosk sí es público |
| Auth en servidor para turno | Source of truth = guard; el cliente no «esconde» nombres de banda |
| Puerto 3021 | Evitar colisión con PREGÓN :3020 / MATIZ :3019 / ZAGUÁN :3018 |
| Web (no PWA Must) | S2: kiosk de pasillo + móvil; install Could L+1 |
code TM-XXXX | Ticket humano, no UUID en el pasillo |
Unique (room, day, slot) | Dos bandas no caben a la misma hora |
5. Variables
.env local (nunca git):
| Variable | Servicio | Descripción |
|---|---|---|
DATABASE_URL | API | Neon divine-haze-05909195 |
JWT_SECRET | API | Firma tokens |
PORT | API | opcional, 3021 |
JWT_EXPIRES | API | opcional (p. ej. 12h) |
.env.example solo placeholders.
Web: URL de API en ApiService (default http://localhost:3021/api). Proxy Angular proxy.conf.json → :3021.
6. Dependencias de producto (mínimas)
API
@nestjs/common/core/platform-express- JWT (
joseo@nestjs/jwt) bcrypt(obcryptjs)- cliente Postgres (
pg/@neondatabase/serverless) o Prisma class-validator+class-transformer
Web
- Angular standalone
- Tailwind 3
- fuentes: Fraunces + Atkinson Hyperlegible (Google Fonts o self-host)
7. Arranque (contrato)
cd /Users/cristian/orca/temple-app
# instalar apps independientes (npm --prefix o pnpm --filter)
# apps/api/.env → DATABASE_URL + JWT_SECRET + PORT=3021
# migrate / ensureSchema + seed
# api → http://localhost:3021
# web → http://localhost:4200
8. Lo que este stack no es
| No | Por qué |
|---|---|
| npm workspaces | AP-06 |
| Firebase Auth | Stack fijo JWT + Neon |
| Next.js / React | D-P0-03 |
| Pasarela / Stripe Must | S4: ventanilla |
| Redis / colas | 15 slots no lo necesitan |
| Ticketing / aforo | Hora ≠ concierto |
| 112 / CAD | TEMPLE no es 112 |
| Chat / kanban API | Terna distinta |
9. Nota sobre el repo
[COMPROBADO] Path previsto /Users/cristian/orca/temple-app y remoto Criscode2022/temple-app.
El código se escribe en paralelo. Esta suite define el contrato TEMPLE (rooms + bookings + JWT CONSERJE, health temple-api, puerto 3021). Si el scaffold parte de un día anterior, gana este contrato, no el dominio previo. [DECISIÓN]
07-creative-direction.md
07 — Dirección creativa — TEMPLE
1. Concepto
TEMPLE es un tablero de horas de flight case: se entra al quiosco y se sale con una hora, no una landing de «sala de conciertos». El ground es negro de instrumento. El ámbar es el LED del dial. La joya del ampli sella lo urgente, poco.
Mood elegido: vehicle dashboard.
Primer instinto descartado: nocturnal escenario+neón. Un local de ensayo se opera como un tablero de horas, no como Conciergo.
[COMPROBADO] Mood, ground y paleta salen de docs/00-day-brief.md.
2. Territorio visual
| Eje | Sí | No |
|---|---|---|
| Superficie | Ink #12110F, panel #1E1C18, cream de dial | Fog PREGÓN, yeso MATIZ, hormigón ZAGUÁN, papel MARGEN, musgo CESTA |
| Tipo | Fraunces display + Atkinson Hyperlegible UI | Ibarra+Jost, Libre Baskerville+Nunito, Instrument+Sora, Cormorant+Public Sans, Spectral+Manrope |
| Foto | Sala de ensayo: kit, combo, seca; moqueta, no palco | Escenario, público, neón de concierto, «banda en portada» |
| Grid | 3 salas enormes; rejilla de 2 h; horario | Hero 2-col + 3 cards de features (AP-12) |
| Acento | Amber #E8A317 en coger, bloque libre, LED | Mark lima PREGÓN, amatista chapel, óxido inmobiliario |
| Chrome | Casi sin nav (S-MIN) | Rail de kanban, bottom tabs, masthead, wizard 1—2—3 |
3. Paleta
| Token | Hex | Rol |
|---|---|---|
| Ink / G-INK | #12110F | Ground de página. Negro de instrumento, no fotocopia. |
| Panel | #1E1C18 | Superficie de card / dial / celda. Nunca el fondo de página. |
| Cream | #F4EBD0 | Texto, wordmark, cuerpo. Crema de dial. |
| Amber | #E8A317 | LED / gaffer: CTA Coger, bloque libre, foco |
| Mute | #8C8474 | Meta, labels, hora secundaria, idle |
| Jewel | #C23B22 | Acento secundario, poco: error, urgente, no 112-como-envío |
Jerarquía de color: el ink carga; el amber puntúa; el panel encuadra la sala. Si el amber pinta fondos enteros, deja de ser LED y se vuelve «brand naranja». El jewel no decora el header: solo puntual (error, sello). [DECISIÓN]
4. Tipografía
| Uso | Familia | Tamaños de referencia |
|---|---|---|
| Wordmark | Fraunces 700 | 24–28 desktop · 22 mobile |
| Titular de kiosk / turno | Fraunces 700 | 32–40 |
| Código TM-XXXX | Fraunces 700 | 28–36 |
| Nombre de sala | Fraunces 700 | 22–28 |
| Cuerpo / disclaimers | Atkinson Hyperlegible 400 | 16–17 / 26–28 lh |
| UI, chips, form, rejilla | Atkinson Hyperlegible 400/500/700 | 14 / 16 |
| Meta (hora, m², kind) | Atkinson Hyperlegible 500 | 12–13, tracking 0.04em, mute |
Prohibido: Fraunces por debajo de 20px (se rompe). Atkinson en el wordmark (se vuelve SaaS).
Fuentes vetadas de la serie y del brief: Ibarra Real Nova / Jost / Libre Baskerville / Nunito / Instrument Serif / Sora / Cormorant / Public Sans / Spectral / Manrope / Zilla / Mulish / Newsreader / Outfit / Lora / Karla.
5. Fotografía
Las imágenes del case son el sistema, no un moodboard:
| Asset | Lectura visual | Uso |
|---|---|---|
hero.jpg | Nave / flight case / tablero ámbar, no escenario | Cover UX · atmósfera, no hero de marketing en / |
salas/bateria.jpg | Kit, moqueta, cuarto cerrado | Sala 1 |
salas/combo.jpg | Amp, PA chico, ensayo de grupo | Sala 2 |
salas/seca.jpg | Cuarto seco, sin batería | Sala 3 |
Crop: salas en 4:3 (cuarto). No recorte 16:9 de escenario ni 1:1 de retrato. [DECISIÓN] 4:3 de sala, distinto del 4:3 de incidente PREGÓN (calle) y del 16:10 editorial.
Tratamiento: saturación real, sin LUT «concert purple», sin haze de humo de escenario. El amber no se superpone como filtro: vive en UI.
hero.jpg vive en UX-00 Cover, no como hero de producto en el kiosk. [DECISIÓN] AP-21: 3 salas reales en el fold.
6. Layout
Kiosk (H-KIOSK)
┌─────────────────────────────────┐
│ TEMPLE · La hora, no el concierto.
│ ┌─────────┬─────────┬─────────┐│
│ │ Sala 1 │ Sala 2 │ Sala 3 ││ 3 tiles enormes
│ │ Batería │ Combo │ Seca ││
│ │ 3 datos │ 3 datos │ 3 datos ││
│ └─────────┴─────────┴─────────┘│
└─────────────────────────────────┘
- Wordmark + eslogan (una línea, no portada).
- Lead en el fold: 3 salas (foto, nombre Fraunces, 3 datos Atkinson).
- Cada tile es la acción. No hay que cazar un CTA de marca.
No hay portada fotográfica a 60vh. [DECISIÓN]
390: las mismas 3 salas apiladas, no un carousel.
Rejilla (F-BOOK)
Sala 2 Combo
[10–12 cogida] [12–14 cogida] [16–18 cogida]
[18–20 LIBRE ] [20–22 LIBRE ]
Bloque libre: panel + filete amber.
Bloque cogido: panel + mute; no nombre de banda.
Turno (horario)
Sala 1 Sala 2 Sala 3
10–12 Cuarto Aire Tres Cables Libre
12–14 Libre Cuarto Aire Papel Fumado
16–18 Marta Chen Las Cajas Libre
18–20 Libre Libre Eco Bajo
20–22 Tres Cables Libre Libre
Cabecera S-MIN: TEMPLE · Hoy · Lola · Salir.
No rail. No columnas Recibido / En curso.
390: una sala debajo de otra, mismas filas de hora.
Ticket
Código Fraunces, sala + bloque Atkinson, disclaimers cream sobre ink. Sin confetti. Sin escenario.
Login
Columna estrecha sobre ink. Dial, no splash de concierto.
7. Motion
| Superficie | Spec |
|---|---|
| Hover tile sala | Rule cream 1px; no elevación 8px ni scale 1.04 |
| Coger hora | Fade 160ms al ticket; off si reduced-motion |
| Bloque libre | Amber LED estático; no parpadeo |
| Skeleton | Pulso 1.2s en panel/ink; off si reduced-motion |
Prohibido: parallax de escenario, scroll-jacking, page transitions de 400ms, neón parpadeante, animación de público aplaudiendo al coger (mentiría concierto).
8. Anti-clichés (serie ALS-2)
| Cliché | Por qué no |
|---|---|
| Escenario + neón / nocturnal | Primer instinto del brief; vetado (Conciergo) |
| Highlighter fog + lima (PREGÓN) | Bando, no ensayo |
| Capilla amatista (MATIZ) | Oficio de color |
| Hormigón + óxido (ZAGUÁN) | Finca |
| Papel + cadmio kiosco (MARGEN) | Editorial |
| Botanical / musgo (CESTA) | Despensa |
| «Banda feliz en portada» stock | Mentira social del concierto |
| Azul institucional de taquilla | Entradas; contradice R-HY dashboard |
| Iconos outline de guitarra 2014 | Chrome tipográfico + foto real bastan |
9. Tono de marca (visual + verbal, puente a doc 09)
Cercano de pasillo y de mesa. Tuteo en UI al músico. Segunda persona cuando habla la interfaz. Tercera cuando habla el turno (Marta Chen ocupa…).
El producto se coge y se mira en un horario. No vende entradas, no es escenario, no es 112, no es kanban.
10. Criterios de aceptación creativos
- Ground de página =
#12110F. Cards =#1E1C18. Nunca al revés. - Amber en el CTA Coger y en el bloque libre, no un header naranja lleno.
- 3 salas visibles en el primer viewport (lead + 3 datos).
- Ninguna fuente de la lista vetada. Fraunces + Atkinson Hyperlegible.
- Home reconocible como quiosco de salas, no como hero 2-col de concierto.
- Success no celebra un «ya estáis en el escenario» ni una entrada.
- Jewel solo en error / sello, no en el chrome.
- Turno = horario. Cero columnas Recibido / En curso.
08-design-system.md
08 — Design system — TEMPLE
1. Tokens
--color-ink: #12110F; /* G-INK ground */
--color-panel: #1E1C18; /* cards / dial / celda */
--color-cream: #F4EBD0; /* texto, wordmark */
--color-amber: #E8A317; /* LED / gaffer */
--color-mute: #8C8474; /* meta */
--color-jewel: #C23B22; /* urgente, poco */
--font-display: "Fraunces", "Iowan Old Style", serif;
--font-ui: "Atkinson Hyperlegible", system-ui, sans-serif;
--radius-card: 4px; /* dial, no pill de SaaS */
--radius-cta: 4px;
--rule-led: 2px solid var(--color-amber);
--space: 4 / 8 / 12 / 16 / 24 / 32 / 48 / 64;
Tailwind (referencia):
| Key | Valor |
|---|---|
colors.ink | #12110F |
colors.panel | #1E1C18 |
colors.cream | #F4EBD0 |
colors.amber | #E8A317 |
colors.mute | #8C8474 |
colors.jewel | #C23B22 |
fontFamily.display | Fraunces |
fontFamily.sans | Atkinson Hyperlegible |
[COMPROBADO] Hex y tipo = brief.
2. Escala tipográfica
| Token | Familia | Size / lh | Uso |
|---|---|---|---|
display-l | Fraunces 700 | 40 / 44 | Titular turno desktop · código ticket |
display-m | Fraunces 700 | 28 / 32 | Nombre sala · wordmark |
display-s | Fraunces 700 | 22 / 28 | Nombre sala 390 |
code | Fraunces 700 | 24 / 28 | TM-XXXX |
body | Atkinson 400 | 16 / 26 | Disclaimers, confirmar |
ui | Atkinson 400 | 16 / 24 | Form, lista, rejilla |
meta | Atkinson 500 | 13 / 18 | Hora, m², kind |
slot | Atkinson 700 | 16 / 20 | 10–12 · Libre / Cogida |
3. Componentes
RoomTile (H-KIOSK)
| Spec | Valor |
|---|---|
| Desktop | 3 columnas iguales, min-height ~520–640, foto 4:3 cover |
| 390 | 1 col, misma foto + 3 datos, target ≥44 |
| Contenido | nombre Fraunces · lead · kind · m² · «N de 5 libres» |
| Superficie | panel sobre ink |
| Hover | rule 1px cream |
| Toda la tile | <a> a /sala/:slug |
Lead + 3 datos visibles sin hover. [DECISIÓN] AP-21.
SlotGrid (F-BOOK)
┌──────────────┐
│ 18–20 │ Fraunces/Atkinson 16
│ Libre │ amber si free; mute si taken
└──────────────┘
- Libre: filete amber 2px, texto cream, CTA implícito.
- Cogida: panel, texto mute,
aria-disabled, sin nombre de banda. - Target ≥44 (mejor ≥56 en kiosk de pasillo).
- 5 celdas en orden de slot.
ConfirmSheet (UI-04)
| Spec | Valor |
|---|---|
| Desktop | Panel derecho o modal no-modal bajo la rejilla, max 480 |
| 390 | Hoja inferior, safe-area |
| Campos | bandName · label visible |
| CTA | Coger hora · fondo amber · texto ink · h-44 |
| Disclaimers | «Hora cogida ≠ concierto.» · «Se paga en ventanilla.» |
| Cerrar | Volver a la rejilla |
Ticket (UI-05)
Código display-l, sala + bloque body, 4 disclaimers, CTA secondary Coger otra.
Login
Columna max 400 sobre ink. Inputs panel, rule mute, foco outline 2px amber offset 2.
TurnoMatrix (UI-07)
| Spec | Valor |
|---|---|
| Desktop | Tabla 5 filas × 3 columnas + cabecera de salas |
| Celda taken | panel + bandName cream |
| Celda free | «Libre» mute |
| Cabecera | Fraunces 22 salas · Atkinson 13 horas |
| 390 | 3 bloques apilados (una sala cada uno), mismas filas |
No es un kanban. No hay chips Recibido / En curso. [DECISIÓN]
Botones
| Variante | Uso | Spec |
|---|---|---|
| Primary | Coger hora, Entrar | Fondo amber, texto ink, h-44, radius 4 |
| Secondary | Coger otra, volver | Rule cream, texto cream, fondo ink |
| Ghost | Turno (en kiosk), Salir, Reintentar | Texto mute |
| Danger | Error 409 / red (no es CTA de envío) | Texto jewel, no botón de acción primaria |
Pending: disabled + aria-busy. No spinner de marca.
Contraste primary: amber #E8A317 + texto ink #12110F (no texto blanco sobre ámbar). [DECISIÓN]
Form
Labels visibles (no placeholder-only). Inputs h-44, radius 4, rule mute 50%, foco outline 2px amber offset 2. Fondo panel, texto cream.
Estados
| Estado | Receta |
|---|---|
| Empty kiosk | Titular Fraunces 28 + 1 línea Atkinson |
| Empty slots | Titular + 1 línea · «Hoy no queda hora en esta sala.» + ← Salas |
| Error | Banner filete jewel + texto + Reintentar |
| Loading kiosk | 3 tiles panel |
| Loading slots | 5 celdas |
| Loading turno | matriz 5×3 |
| 404 sala | «Esa sala no está.» + link al kiosk |
| 409 | «Esa hora ya está cogida.» + rejilla |
4. Grid y breakpoints
| Viewport | Comportamiento |
|---|---|
| ≥1200 | Kiosk 3 col; slots max 720; turno matriz completa |
| 960–1199 | Kiosk 3 col compactas; turno matriz |
| 600–959 | Kiosk 1 col; turno apilado por sala |
| ~390 | Kiosk 1 col; slots 1–2 col; confirmar hoja; turno apilado |
Padding horizontal: 24 desktop, 16 mobile.
5. Iconografía
Mínima. El quiosco no es un set de iconos outline de guitarra.
| Sitio | Recurso |
|---|---|
| Kind | Texto (Batería / Combo / Seca). Icono trazo 1.5 de 20px opcional |
| Libre | Filete amber, no check clip-art |
| Empty | Nada o una rule amber de 32px |
| Status | Texto Libre / Cogida, no semáforo solo-color |
Si hace falta un icono (salir, error): trazo 1.5, 20px, cream. No pack Remix/Lucide a color.
6. Elevación y borde
| Superficie | Tratamiento |
|---|---|
| Página | Ink plano |
| Tile / slot / celda | Panel plano + rule 1px mute 30% |
| Libre | + filete amber |
| Modal | No hay modal Must (confirmar es hoja/panel) |
Cero sombras shadow-lg. El flight case no flota.
7. Mapa componente → ruta
| Componente | Rutas |
|---|---|
KioskBoard | / |
RoomTile | / |
SlotGrid | /sala/:slug |
ConfirmSheet | /sala/:slug |
OkArticle | /ok/:code |
LoginForm | /login |
TurnoHeader | /turno |
TurnoMatrix | /turno |
EmptyState / ErrorBanner / SkeletonKiosk / SkeletonSlots / SkeletonTurno | /, /sala/:slug, /turno |
8. Criterios de aceptación DS
- Tokens Tailwind = hex del brief, sin fog PREGÓN
#F1F3F6como ground. - Cards en panel; página en ink.
- Primary CTA amber + texto ink (nunca mute sobre ink como único CTA).
- Fraunces no aparece en labels de form ni en meta 12px.
- Recorte de sala
aspect-[4/3], no 16:9 de escenario. - Targets de tiles, slots y CTA ≥44px (slots kiosk ≥56 preferible).
- 3 datos de sala visibles sin hover.
- Fuentes: Fraunces + Atkinson Hyperlegible. Cero Ibarra / Jost leftover.
09-content-guide.md
09 — Guía de contenido — TEMPLE
1. Voz
Cercana de pasillo y de mesa. Tuteo en UI al músico. Segunda persona cuando la interfaz habla. Tercera cuando habla el turno (Marta Chen ocupa…).
Sin jerga de concierto («esta noche en cartel», «tu público te espera», «compra tu entrada»). Sin taquilla. Sin «reserva tu slot» de Booksy. Sin sirena. Sin kanban en UI.
El producto se coge y se mira en un horario. No vende entradas, no es escenario, no es 112, no es chat.
2. Palabras permitidas / prohibidas
| Usar | No usar |
|---|---|
| Hora / bloque / coger | Entrada, ticket de concierto, aforo, puerta |
| Sala | Escenario, palco, recinto, venue |
| Ticket (de hora) / código | Entrada, pase, backstage |
| Cogida / libre | Reservado Booksy, «confirmada la cita», «en cartel» |
| Turno / ocupación / horario | Kanban, Recibido, En curso, mesa de partes |
| Banda / nombre de banda | Rider, backline extra, rider técnico |
| Ventanilla | Pagar ahora, Stripe, TPV (en UI) |
| TEMPLE no vende entradas | Comprar, taquilla, Conciergo |
«Kanban» y «F-BOOK» son lenguaje de diseño, no de UI: Iván no lee «booking»; Lola lee Libre / cogida y nombres.
«Ticket» en UI es el acuse de hora. Si hay ambigüedad, preferir código o hora cogida. [DECISIÓN]
3. Microcopy duro (literales irrenunciables)
El brief fija oposiciones. Aparecen donde el usuario puede confundirse.
| Oposición | Dónde | Copy |
|---|---|---|
| Hora cogida ≠ concierto | Confirmar sobre CTA · ticket · pie de kiosk | «Hora cogida no es concierto. TEMPLE no pone un escenario.» |
| Sala ≠ escenario | Tile de sala · ticket · turno pie | «Esto es una sala, no un escenario. Es un cuarto con moqueta.» |
| TEMPLE no vende entradas | Ticket · confirmar · login pie | «TEMPLE no vende entradas. Se paga la hora en ventanilla.» |
| Ensayar no es actuar | Ticket · kiosk pie | «Ensayar no es actuar. El concierto es otro producto.» |
[DECISIÓN] Los cuatro textos son obligatorios en UI. No se diluyen a un tooltip.
Pie de kiosk puede condensar dos en dos líneas; ticket muestra los cuatro.
4. Microcopy por superficie
| Superficie | Copy |
|---|---|
| Eslogan | La hora, no el concierto. |
| Línea de nave | TEMPLE · Carabanchel |
| Kiosk titular | TEMPLE |
| Tile dato 1 | Batería / Combo / Seca |
| Tile dato 2 | 12 m² / 18 m² / 10 m² |
| Tile dato 3 | 2 de 5 libres |
| Sala volver | ← Salas |
| Slot libre | Libre |
| Slot taken | Cogida |
| Confirmar titular | Coger 18–20 |
| Confirmar nombre | Nombre de la banda |
| Confirmar submit | Coger hora |
| Confirmar disclaimer 1 | Hora cogida no es concierto. |
| Confirmar disclaimer 2 | Se paga en ventanilla. TEMPLE no vende entradas. |
| Login titular | Entrar al turno |
| Login ayuda | Solo conserje. La banda coge hora en el kiosk, sin cuenta. |
| Login submit | Entrar |
| Login error | Email o contraseña no valen. |
| Login volver | Volver al kiosk |
| Empty kiosk | Aún no hay salas. |
| Empty slots | Hoy no queda hora en esta sala. |
| Empty turno | Hoy no hay horas apuntadas. |
| Success titular | Hora cogida. |
| Success código | TM-2109 |
| Success cuerpo | Hora cogida no es concierto. TEMPLE no vende entradas. |
| Success sala | Sala ≠ escenario. Ensayar no es actuar. |
| Success CTA | Coger otra |
| Error | No hemos podido cargar el kiosk. |
| Error retry | Reintentar |
| Error 409 | Esa hora ya está cogida. |
| Loading kiosk | Abriendo las salas… |
| Loading slots | Abriendo las horas… |
| Loading turno | Abriendo el turno… |
| 404 sala | Esa sala no está. |
| Turno titular | Turno |
| Celda libre | Libre |
| Salir | Salir |
| Link Turno (kiosk) | Turno |
5. Salas y horas seed (tono)
Las salas demo se escriben como cuarto de ensayo, no como ficha de concierto ni como anuncio.
| Pieza | Tono |
|---|---|
| Sala 1 Batería | Kit dentro. Moqueta. Sin palco. |
| Sala 2 Combo | Amp y PA chico. Grupo. |
| Sala 3 Seca | Sin batería. Escritura / acústico. |
| TM-2104 Marta Chen | Nombre de baterista; no rider. |
| Los Yesos (POST) | Banda de Iván; dos palabras, sin biografía. |
No inventar declaraciones de músicos reales. Si hay una voz, es de persona de diseño etiquetada.
En CONFIRMED no se reescribe a «ya estáis en el escenario». El cierre es la hora cogida. [DECISIÓN]
6. Nombres propios del seed
| Nombre | Uso |
|---|---|
| Iván Mora | BANDA; sin cuenta; guitarra, Los Yesos |
| Lola Rivas | CONSERJE; lola@temple.nave |
| Marta Chen | BATERÍA; sin cuenta; seed Sala 1 16–18 |
| Los Yesos | Banda de Iván; POST demo |
| Cuarto Aire, Tres Cables, Papel Fumado, Las Cajas, Eco Bajo | Bandas catálogo |
| TEMPLE · Carabanchel | Nave demo; Paseo de Yeserías |
No inventar CIF de nave, teléfono de taquilla, ni cartelera real como si fuera el producto. [SUPUESTO de catálogo demo]
Paseo de Yeserías / Carabanchel son topónimos reconocibles, no un inventario oficial de un local 2026.
7. Tono por estado
| Status | Frase UI | Frase que Lola podría decir (fuera de app) |
|---|---|---|
| Libre | Libre | «Está libre. Cogedla en el quiosco.» |
| Cogida / CONFIRMED | Cogida | «Esa hora está cogida. No es un concierto.» |
La app no envía esos mensajes a la banda en v1. El copy solo prepara el habla. No hay email de «ya tenéis escenario».
8. Capitalización y números
- Wordmark: TEMPLE en versales Fraunces (sin tilde).
- Código:
TM-2109(TM versales, guion, 4 dígitos). - Nombres: Iván Mora, Lola Rivas, Marta Chen.
- Salas: Sala 1 Batería (mayúscula de Sala + kind).
- Bloques:
10–12en UI (en-dash);10-12en API. - Fecha:
21 agoen cabecera de turno;viernes 21 de agostosi hay línea larga. - No mezclar
tm-2109en minúsculas en UI. API puede normalizar a versales.
9. Idioma
es-ES. Fácil lectura. EN no en v1.
No mezclar «booking» en UI. En API sí: bookings, slot, bandName, status.
«Banda» en UI cuando hablamos de Iván; «batería» para Marta; «el músico» genérico en copy de sistema. [DECISIÓN]
10. Accesibilidad de copy
- No transmitir estado solo con color (el amber no «significa» libre él solo).
- Celdas llevan texto: Libre / Cogida / nombre de banda.
- Aviso de no-entradas lleva palabras, no solo el jewel.
- Alt de fotos: sala + kind, no «imagen1».
- hero: «Nave de ensayo y flight case; tablero de horas, no escenario.»
- bateria: «Sala de batería con kit; cuarto de ensayo.»
- combo: «Sala combo con ampli y PA chico.»
- seca: «Sala seca, sin batería.»
11. Piezas que no se escriben
| No | Motivo |
|---|---|
| «Tu entrada ha sido emitida» | TEMPLE no vende entradas |
| «Ya estáis en el escenario» | Hora cogida ≠ concierto |
| «Comprar ahora» / «Taquilla» | S4 · ventanilla |
| «Si es urgente, coge aquí» (como 112) | TEMPLE no es 112 |
| Recibido / En curso / Cerrado | No es kanban |
| Ranking de las bandas de la nave | Likes, otro producto |
| Lorem / «lorem ipsum sala» | Prohibido en el case |
| Declaraciones inventadas de una nave real | Verdad de catálogo |
10-accessibility.md
10 — Accesibilidad — TEMPLE
Objetivo: WCAG 2.2 AA. No se declara conformidad legal certificada.
Este documento cubre la UI (kiosk, horas, ticket, login, turno). No audita la accesibilidad física de la nave, del pasillo ni de las salas. [SUPUESTO]
1. Decisiones
| Tema | Decisión |
|---|---|
| Tipo UI | Atkinson Hyperlegible ≥16px body |
| Display | Fraunces no se usa por debajo de 20px |
| Contraste | Cream #F4EBD0 sobre #12110F / #1E1C18 |
| CTA amber | Texto ink sobre #E8A317 |
| Jewel error | Texto jewel sobre ink o jewel + cream, nunca jewel sobre amber |
| Foco | Outline 2px amber, offset 2px, visible (no outline-none global) |
| Tiles | <a> con nombre + 3 datos en texto |
| Rejilla | Labels visibles; aria-pressed / aria-disabled en slots |
| Imágenes | alt = sala + kind |
| Form | Labels visibles, no placeholder-only |
| Errores | Texto, no solo color |
| Mobile / kiosk | Targets ≥44px (tiles, slots, Coger) · S2 funda en el suelo |
| Movimiento | Fade 160ms; prefers-reduced-motion: reduce → 0 |
| Live regions | aria-live="polite" en empty/error de kiosk, slots y turno |
2. Contraste (comprobación de diseño)
| Par | Uso | Nota |
|---|---|---|
#F4EBD0 / #12110F | Body sobre ink | Pasa AA y AAA cuerpo |
#F4EBD0 / #1E1C18 | Body sobre panel | Pasa AA |
#12110F / #E8A317 | CTA Coger | Pasa AA para texto ≥14px bold; no usar blanco sobre amber |
#8C8474 / #12110F | Meta mute | Verificar ≥13px; no usar en 11px |
#8C8474 como texto 12px sobre panel | — | Prohibido para body |
| Slot idle mute | Solo si no es el único indicador | + label textual Libre / Cogida |
#C23B22 / #12110F | Error 409 | Verificar ≥16px; si falla, cream + rule jewel |
| Blanco / amber como texto | — | Prohibido (ámbar + blanco falla en UI pequeña) |
3. Teclado
| Flujo | Orden |
|---|---|
| Kiosk | Wordmark → tile 1 → 2 → 3 → link Turno |
| Sala | Atrás → slots en orden → (confirmar: nombre → Coger) |
| Ok | Código (lectura) → Coger otra |
| Login | Email → password → submit → volver al kiosk |
| Turno | Salir → recorrido de celdas por fila |
- Enter en tile = navegar a sala.
- Enter en slot libre = abre confirmar.
- Enter en slot cogido = no POST; anuncia «Cogida».
- Escape cierra confirmar (vuelve a rejilla) si el confirmar está abierto.
- Focus trap: no hay modal Must; la hoja 390 no trampa si hay ← Salas.
- En 390, la hoja no debe robar el foco al cargar la rejilla.
4. Semántica
| Pieza | Markup |
|---|---|
| Kiosk | <main> · lista de salas <ul> o <nav aria-label="Salas"> |
| Tile | <a> · incluye nombre, kind, m², libres en texto |
| Rejilla | <section aria-label="Horas de hoy"> |
| Slots | role="group" + aria-label="Bloques" · botones |
| Slot taken | aria-disabled="true" |
| Slot selected | aria-pressed="true" |
| Confirmar | <form aria-label="Coger hora"> |
| Turno | <table> o grid con role="table" · encabezados de sala y hora |
| Aviso no-entradas | texto normal; no alert de envío |
| Skeletons | aria-busy="true" en el contenedor; aria-hidden en placeholders |
5. Lector de pantalla — copy
| Situación | Anuncio |
|---|---|
| Tile | «Sala 2 Combo. Amp + PA chico. Combo. 18 metros. 2 de 5 libres.» |
| Slot libre | «18–20, libre» |
| Slot cogida | «10–12, cogida» |
| Ticket | «Hora cogida. Hora cogida no es concierto. Código TM-2109.» |
| Empty kiosk | «Aún no hay salas.» |
| Empty slots | «Hoy no queda hora en esta sala.» |
| Error | Anuncio en live region; foco al banner |
| 409 | «Esa hora ya está cogida.» |
| Celda turno | «Sala 1 Batería, 16–18, Marta Chen» / «Sala 2 Combo, 18–20, libre» |
6. Producto vs nave física
| Lo que TEMPLE puede hacer | Lo que no afirma |
|---|---|
| Targets 44px en el pasillo | Que el pasillo de Yeserías sea accesible de hecho |
| Kiosk usable con teclado, zoom 200% y letra 16px | Que la nave tenga rampa, bucle o mostrador accesible |
| Copy «no vende entradas» | Que no exista un concierto en otro producto |
| Autoría con nombre de banda libre | Que Los Yesos sea identificable de forma legal |
| Foto de sala con alt | Que la sala física cumpla CTE / aislamiento |
[DECISIÓN] v1 no incluye auditoría a11y de la nave. bandName es dato de hora demo, no un certificado de identidad.
7. Riesgos
| Riesgo | Mitigación |
|---|---|
| Hoja confirmar tapa la rejilla en 390 | padding-bottom / scroll al form |
| Fraunces en meta 12px | Prohibido; meta = Atkinson 13 |
| Amber como único estado de libre | + label Libre |
| Foto sin alt | Checklist seed: 3 alts + hero |
| 409 leído solo por color jewel | Label siempre |
| Iván con funda (S2) | Targets ≥44; no gestos swipe; no hover-only; sin cuenta |
| CTA amber + texto blanco | Texto ink |
| Leftover Ibarra / Jost / fog | Tokens TEMPLE |
| Matriz turno ilegible en 390 | Apilar por sala, no 3 col de 120px |
8. QA a11y (mínimo)
| # | Prueba | Pasa si |
|---|---|---|
| 1 | Teclado kiosk → sala → slot → ok | Sin trampa; foco visible |
| 2 | Teclado login → turno | Acciones alcanzables |
| 3 | Zoom 200% móvil 390 | Slots usables; confirmar no solapa inputs |
| 4 | Lighthouse a11y ≥ 90 en / | Sin contrast fails de tokens |
| 5 | VoiceOver/NVDA: tile y slot anunciados | Nombre, hora, libre/cogida comprensibles |
| 6 | prefers-reduced-motion | Sin stagger ni slide |
| 7 | Contraste CTA amber + error jewel | Texto ink sobre amber; 409 con texto |
9. Criterios de aceptación
- Ningún control de tile, slot o CTA mide menos de 44×44 CSS px.
- El disclaimer no depende del color amber o jewel para ser entendido.
- Las 3 fotos de sala + hero tienen
altno vacío y no genérico. - El foco no se pierde al reintentar un error de red o un 409.
- En 390 las 3 salas son alcanzables sin un carousel de marketing.
- Un turno no se anuncia en
/sin token (no hay HTML público de nombres ajenos). - Iván puede completar coger hora solo con teclado y sin cuenta.
11-privacy-security.md
11 — Privacidad y seguridad — TEMPLE
1. Datos que existen
| Dato | Dónde | Base / nota |
|---|---|---|
| Email y hash de la conserje | users | Contrato interno del turno |
| Nombre de banda en la hora | bookings.band_name | Texto libre; no es una cuenta |
| Sala, día, bloque | bookings | Hora; catálogo seed · PII de atrezzo |
| Foto de sala | rooms.cover filename | Seed; no UGC v1 |
| Salas | rooms | Catálogo; no PII |
| Sesión JWT | Authorization + sessions? | Solo CONSERJE |
No se pide cuenta a la banda. No hay DNI, email ni teléfono de Iván en producto. No hay tracking de menores. Las fotos seed no se presentan como un local real.
2. Minimización
| Qué no se recoge en v1 | Por qué |
|---|---|
| Email / teléfono / DNI de la banda | H3 · no taquilla · no seguimiento |
| Geolocalización del dispositivo | Kiosk de pasillo |
| Rider / backline extra | S4 |
| Pago / tarjeta | S4 · ventanilla |
| Foto subida por la banda | No hay UGC Must |
| IP como identidad | No se usa como usuario |
| Nombres de otras bandas en el kiosk | D9 |
bandName es dato de hora demo, no un requisito de identidad legal. L+1 podría hacerlo opcional. [DECISIÓN]
3. Seguridad L2
| Control | Spec |
|---|---|
| Auth turno | JWT Bearer · role === CONSERJE |
| Password | bcrypt cost 12; nunca en response |
| Lectura turno | GET /api/turno → 401 sin token |
| Kiosk / POST hora / rooms / health / login | Públicos |
| Rate limit | /auth/login + POST /api/bookings (anti stuffing / spam; Should si no llega al slice) |
| CORS | Origen http://localhost:4200 en local |
| Secretos | Solo .env (no git) |
| Cover allowlist | Filenames seed; no URL arbitraria |
next post-login | Paths relativos allowlist (/turno) |
| Guard web | Angular en /turno |
| Ticket público | /ok/:code no hidrata GET turno |
| Unique slot | 409; no overbooking |
| Kiosk slots | free / taken sin bandName |
No se declara cumplimiento RGPD definitivo. Sí: minimización, turno JWT y derecho a borrar la cuenta de conserje (manual L2). Las horas seed se tratan como datos de demo, no como encargo de tratamiento de una nave real.
4. Superficies de riesgo
| Riesgo | Mitigación v1 |
|---|---|
| Enumeración de códigos TM-XXXX | GET turno 401 sin token; ticket no lista otras horas |
| JWT en localStorage | Aceptable en demo; horas son atrezzo, no PII real de nave |
| Nombre de Marta en seed | El kiosk no lista bandas ajenas (D9) |
Foto de sala en public/ | Inevitable para el seed; no hay listado público de bookings |
| Spam de POST bookings | Unique + rate limit Should; bandName max 80 |
| Lola pide un kanban | D14: no hay fila de status de columnas |
Iván pega un teléfono en bandName | Copy: «nombre de la banda»; no se pide; no se scrape |
Open redirect next | Allowlist /turno |
| Double-book | UNIQUE + 409 |
| Carrera de dos POSTs al mismo slot | Constraint de BD gana; el segundo 409 |
5. Roles y autorización (recordatorio)
| Recurso | Anónimo | CONSERJE |
|---|---|---|
| GET rooms / :slug / health / POST bookings / POST login | Sí | Sí |
| GET turno (nombres de banda) | 401 | Sí |
| Entradas / 112 / kanban | No existe | No existe |
Iván, Marta y la dueña no tienen fila en users.
6. Criterios de aceptación
- Response de login no incluye
passwordnipassword_hash. - GET
/api/turnosin Bearer es 401, no 200 con nombres. - POST
/api/bookingssin Bearer es 201 (público) o 409. - GET
/api/roomsy GET/api/rooms/combosin Bearer son 200. - GET
/api/rooms/:slugno incluyebandNameen slots. - No hay formulario público que pida DNI, email o teléfono.
/turnosin token redirige a/login(no renderiza nombres en HTML anónimo)./ok/:codeno llama a GET JWT..envno se commitea.- Health no filtra datos:
{ ok: true, service: "temple-api" }.
12-analytics.md
12 — Analítica — TEMPLE
North star: % de bloques ocupados sin WhatsApp (booking_create / capacidad 15 de hoy, ligado a kiosk — no a un mensaje de grupo).
Instrumentación modelo. No hay proveedor conectado en v1 salvo que el build añada un logger local. [DECISIÓN] No se inventan cifras de conversión.
1. Eventos
| Evento | Cuándo | Props mín. |
|---|---|---|
kiosk_view | Render de / | rooms (0–n), freeTotal |
room_open | Render de /sala/:slug | slug, free |
slot_select | Tap slot libre | slug, slot |
booking_create | POST 201 | code, slug, slot |
booking_conflict | POST 409 | slug, slot |
ok_view | Render de /ok/:code | code |
conserje_login | JWT ok | — |
turno_view | Render de /turno | taken, free |
kiosk_empty | 0 salas | — |
slots_empty | 0 libres | slug |
error_banner | UI-09 | surface |
2. Qué no se mide
| No evento | Motivo |
|---|---|
signup_click / lead_submit | No existe CTA de cuenta de banda |
ticket_purchased / entrada_sold | TEMPLE no vende entradas |
emergency_call | TEMPLE no es 112 |
kanban_move | No hay columnas |
concert_checkin | Ensayar no es actuar |
like / favorite | Fuera |
| Identidad de Iván como usuaria | H3 · no es usuaria |
bandName enviado a un tercero | PII potencial |
Hipótesis H2: ok_view sin entrada_claim (el copy contradice). Si en un test de 5 músicos alguien dice «ya tengo entrada», se anota en research futuro, no como KPI inventado.
3. Funnel modelo
Banda: kiosk_view → room_open → slot_select → booking_create → ok_view
Conserje: conserje_login → turno_view
Activación banda = primer booking_create.
Activación turno = primer turno_view con token.
North star de sesión de demo: de los 15 bloques del día, cuántos se ocupan desde el kiosk (seed + POSTs), no desde un WhatsApp fuera de producto.
El seed no cuenta como conversión de kiosk. [DECISIÓN]
4. Integridad (producto, no vanidad)
| Señal | Cómo se observa |
|---|---|
| Turno cerrado | GET /turno 401 sin token (QA, no analytics) |
| Kiosk abierto | POST bookings 201 sin token |
| Expectativa de entrada | Comentarios cualitativos; cero evento ticket_purchased |
| Expectativa de 112 | Cero evento de llamada como conversión |
| Choque de hora | booking_conflict 409 |
| Salud | 4xx/5xx de rooms / bookings |
5. Privacidad de analítica
Sin PII extra. code es identificador de hora (TM-2109), no un email. bandName no se envía a un tercero. Ver doc 11.
6. Criterios de aceptación (si se instrumenta)
- Los eventos de §1 tienen nombre estable.
- No se dispara ningún evento de lead / entrada / 112-como-conversión / kanban / concierto.
- Un bloqueador de cookies no rompe el kiosk (analítica no es Must de runtime).
slugyslotse miden;bandNameno.
13-qa-test-plan.md
13 — Plan de pruebas — TEMPLE
1. Smoke obligatorio (D-P1-06)
| # | Acción | Esperado |
|---|---|---|
| 1 | GET /api/health | 200 · { ok: true, service: "temple-api" } |
| 2 | GET /api/rooms | 200 · 3 slugs bateria, combo, seca |
| 3 | POST /api/auth/login lola@temple.nave / password123 | 200 · accessToken · user.role=CONSERJE |
| 4 | GET /api/turno con Bearer | 200 · 8 taken / 7 free · códigos TM-2101…2108 |
| 5 | ng build o serve web | Web arranca o build OK |
[COMPROBADO] Smoke = health (temple-api) + rooms públicos + login JWT + turno JWT.
2. Casos funcionales
| ID | Caso | Esperado |
|---|---|---|
| S1 | Códigos seed | GET turno incluye TM-2101…TM-2108 |
| S2 | Turno sin JWT | 401 (no 200 con nombres) |
| S3 | Rooms sin JWT | 200 |
| S4 | Room slug sin JWT | 200 · slots sin bandName |
| S5 | POST bookings sin JWT | 201 · status=CONFIRMED · code TM-XXXX |
| S6 | POST Combo 18-20 Los Yesos | 201 · roomSlug=combo · slot=18-20 |
| S7 | POST mismo slot otra vez | 409 SLOT_TAKEN |
| S8 | Slug inexistente | 404 |
| S9 | Kiosk UI | / muestra 3 salas (lead + 3 datos); cero cuenta / entradas |
| S10 | Home es kiosk | / es H-KIOSK; no hero 2-col; no chat PREGÓN |
| S11 | Rutas turno | /turno sin token → /login |
| S12 | Login malo | 401 · mensaje en form |
| S13 | Empty kiosk | 0 salas → UI-08 |
| S14 | Empty slots | sala sin libres → UI-08 |
| S15 | API caída | UI-09 + Reintentar conserva la vista |
| S16 | Loading | Skeleton 3 tiles / rejilla / matriz |
| S17 | Mobile 390 | 3 salas apiladas; slots ≥44px; confirmar usable |
| S18 | Fotos seed | covers bateria.jpg combo.jpg seca.jpg resuelven |
| S19 | Password no viaja de vuelta | login response sin hash |
| S20 | Body POST | acepta roomSlug, slot enum, bandName |
| S21 | Slot inválido | POST slot 14-16 → 400 |
| S22 | Success | /ok/:code copy «Hora cogida no es concierto» · «no vende entradas» |
| S23 | Health | service: "temple-api" |
| S24 | Conteos seed | 8 taken · 7 free |
| S25 | /ok/:code sin JWT funciona | 200 de página; no pide login |
| S26 | Microcopy ×4 | hora≠concierto · sala≠escenario · no entradas · ensayar≠actuar |
| S27 | Puerto API | proceso en 3021 |
| S28 | Turno es horario | no hay columnas Recibido / En curso |
| S29 | Kiosk no filtra nombres | GET :slug sin bandName |
| S30 | Marta en turno | Sala 1 16–18 = Marta Chen |
3. Datos de prueba
| Uso | Valor |
|---|---|
| CONSERJE | lola@temple.nave / password123 |
| Hora feliz seed | TM-2104 · Marta Chen · bateria · 16-18 |
| POST feliz | { "roomSlug":"combo","slot":"18-20","bandName":"Los Yesos" } |
| POST choque | mismo body tras el feliz → 409 |
| Empty kiosk | borrar rooms (solo entorno de test) |
| Empty slots | POST los 7 libres (test) |
4. Regresión de diversidad / craft
| Check | Falla si |
|---|---|
| Home es kiosk | Hay hero 2-col + 3 cards de marca (AP-12) o chat PREGÓN o bento MATIZ |
| Shell es S-MIN | Hay rail de kanban, bottom tabs o chrome 1—2—3 como nav primaria |
| Copy honesto | Ticket dice «entrada» o «escenario» como hecho, o hay «comprar» o CTA 112 de envío |
| Paleta | Se cuelan fog+lima PREGÓN / amatista MATIZ / óxido ZAGUÁN |
| Tipo | Ibarra Real Nova / Jost / Libre Baskerville / Nunito / Instrument / Sora |
| Rutas | Aparecen /mesa, /chat, /entradas, /concierto, /112, /hoy |
| Ground | Página en fog #F1F3F6 o blanco total en vez de ink #12110F |
| Health | service distinto de temple-api |
| Turno | Kanban de 3 columnas |
5. Hipótesis (no se «prueban» en la demo)
H1, H2, H3 requieren uso real. El QA verifica que existen las superficies que permitirían medirlas (kiosk 3 salas, ticket con disclaimer, horario, ausencia de signup de banda, 401 turno, 409 unique).
6. Criterios de salida QA v1
- Smoke §1 en verde (incluido
temple-api). - S2, S5, S7, S9, S10, S17, S22, S26, S28, S29 en verde.
- Cero blockers de copy deshonesto (entrada / escenario-como-hecho / 112-como-envío / kanban).
- Sin
.enven el repo.
7. Fuera de este plan
Playwright e2e completo, carga, fuzzing, auditoría de una nave real.
14-dev-handoff.md
14 — Handoff desarrollo — TEMPLE
1. Arranque
cd /Users/cristian/orca/temple-app
# apps independientes (npm --prefix o pnpm --filter)
# apps/api/.env
# DATABASE_URL= # Neon divine-haze-05909195
# JWT_SECRET=
# PORT=3021
# migrate / ensureSchema + seed
# api → http://localhost:3021
# web → http://localhost:4200
Demo: lola@temple.nave / password123.
El código se escribe en paralelo. Este handoff es el contrato.
2. Paridad Paper
| Debe verse en Angular | Artboard |
|---|---|
| Tokens ink/panel/cream/amber + Fraunces / Atkinson | UI-00 |
| Kiosk home 1440 · 3 salas enormes · lead + 3 datos | UI-01 |
| Kiosk mobile 390 | UI-02 |
| Rejilla bloques 2 h de hoy | UI-03 |
| Confirmar nombre de banda | UI-04 |
| Success ticket «hora ≠ concierto» | UI-05 |
| Login CONSERJE | UI-06 |
| Turno horario (no kanban) | UI-07 |
| Empty | UI-08 |
| Error | UI-09 |
| Loading skeletons | UI-10 |
| Slots mobile 390 | UI-11 |
No clonar PREGÓN (chat + kanban + rail), MATIZ (Hoy bento + editor + bottom tabs), ZAGUÁN (wizard + comparador), MARGEN (lookbook + masthead) ni Conciergo (taquilla).
Paper se construye en paralelo; los nombres de artboard son el inventario planificado (doc 00).
3. Contratos
| Tema | Contrato |
|---|---|
| Health | { ok: true, service: "temple-api" } |
| Salas | GET /api/rooms público |
| Rejilla | GET /api/rooms/:slug público · slots free / taken sin bandName |
| Alta hora | POST /api/bookings público · body roomSlug, slot, bandName |
| Login | { accessToken, user } camelCase (no access_token) |
| Turno | GET /api/turno JWT → matriz con bandName |
| Status enum | CONFIRMED |
| Slot enum | 10-12 | 12-14 | 16-18 | 18-20 | 20-22 |
| Kind / slug | bateria | combo | seca |
| Role | CONSERJE |
| Code | TM-XXXX |
| Choque | 409 SLOT_TAKEN |
| Puerto | 3021 |
Campos JSON en camelCase hacia el web aunque SQL sea snake_case. [DECISIÓN]
4. Mapa de rutas web
| Path | Guard cliente | Página |
|---|---|---|
/ | no | KioskPage |
/sala/:slug | no | SlotsPage (incluye confirmar) |
/ok/:code | no | OkPage |
/login | no (si hay token → /turno) | LoginPage |
/turno | auth | TurnoPage |
Guard: si no hay token, /login?next=. La API es la autoridad para turno.
[COMPROBADO] Solo estas rutas. No implementar /mesa, /chat, /entradas, /concierto, /112.
5. Assets
Copiar desde el case:
2026-08-21-temple/assets/hero.jpg
2026-08-21-temple/assets/salas/bateria.jpg
2026-08-21-temple/assets/salas/combo.jpg
2026-08-21-temple/assets/salas/seca.jpg
→ apps/web/public/assets/salas/ (hero a public/assets/)
cover del seed = filename (bateria.jpg, …).
6. DoD implementación L2
| Check | OK |
|---|---|
| API sirve :3021 | |
| Seed 1 CONSERJE + 3 rooms + 8 bookings 8/15 | |
Smoke health temple-api + rooms + login + turno | |
| JWT protege GET turno; POST bookings público | |
| Unique slot → 409 | |
| Web kiosk + sala + ok + login + turno | |
| Microcopy ×4 | |
| Tokens Tailwind = paleta brief (ink/amber) | |
| Home es kiosk (3 salas enormes) | |
| Turno es horario, no kanban | |
| Fuentes Fraunces + Atkinson Hyperlegible | |
Kiosk no muestra bandName ajenos | |
ng build o equivalente OK | |
| README del repo app con credencial Lola |
7. No hacer
| Prohibido | Motivo |
|---|---|
| npm workspaces | AP-06 |
Commit de .env | Secreto |
| Prometer entrada, escenario-como-hecho, 112 o kanban | Microcopy duro |
Estado RECIBIDO / CURSO / CERRADO | Vocabulario de PREGÓN |
Role OPERADOR / COLORISTA / HOST | Eso es PREGÓN / MATIZ / RONDA |
| Search bar, chat o wizard como home | Rompe H-KIOSK |
| Hero 2-col + 3 cards | AP-12 |
| Pago en kiosk | S4 |
| GET público de bookings con nombres | D9 |
15-roadmap.md
15 — Roadmap — TEMPLE
Este documento no es un cajón de trabajo L2 a medias.
El vertical slice L2 del brief está especificado como done-scope (docs 01, 18, 19).
Aquí solo viven ideas de L+1 / L3 y pulido posterior.
1. Hecho en L2 (esta ejecución documental)
| Entrega | Evidencia |
|---|---|
| Definición producto + terna | docs 00-brief, 01 |
| Personas Iván / Lola / Marta, JTBD, journey | docs 02 |
| IA kiosk-first + chrome S-MIN | docs 03 |
| Flujos F-BOOK + F-TURNO | docs 04 |
| Modelo users / rooms / bookings + seed | docs 05 |
| Stack Angular/Nest/Neon/JWT :3021 | docs 06, 20 |
| Dirección vehicle dashboard + DS | docs 07, 08 |
| Copy Hora ≠ concierto · Sala ≠ escenario · no entradas · ensayar ≠ actuar | docs 09 |
| Paper ref 12 UX + 12 UI | docs 00-paper-reference |
| Suite 00–20 + README + executive | case folder |
2. Implementación L2 (misma complejidad, código)
Contrato en docs 14 y 20. No es deuda silenciosa del case documental: es el build del repo temple-app, en paralelo a esta suite. El alcance L2 ya está cerrado en spec.
Eso no se reabre aquí como «próximo trimestre de producto».
3. L+1 (misma familia, subida de pulido)
| Ítem | Notas |
|---|---|
Ticket público mínimo { code, roomName, slot } | Sigue sin listar otras horas |
| Cancel CONSERJE | No es self-service de banda |
| Grey de bloques ya pasados | Demo v1 no greyea (smoke siempre posible) |
GET /api/me | Turno pinta Lola desde API |
| Rate limit login + POST bookings | Anti stuffing / spam |
| Playwright S1–S30 | CI |
| API URL por environment | Deploy |
prefers-reduced-motion verificado | a11y |
?slot= deep link a confirmar | Must sigue siendo tap en rejilla |
Estas son subidas de pulido, no parches del L2 documental.
[DECISIÓN] No dejar backlog del vertical slice como «mañana». Lo de arriba es L+1.
4. L3 (requiere brief nuevo de diversidad)
- Multi-conserje / multi-nave
- Cuenta de banda y «mis horas»
- Calendario semanal / mes
- Pago / TPV / pasarela
- Entradas / taquilla / Conciergo
- Rider / backline extra
- Chat / kanban
- Integración 112
5. Explícitamente fuera (no backlog disfrazado)
| Ítem | Por qué |
|---|---|
| Entradas / Conciergo | TEMPLE no vende entradas |
| Escenario / line-up | Sala ≠ escenario |
| 112 como canal | TEMPLE no es 112 |
| Chat + kanban | ≠ PREGÓN |
| Cuaderno de fórmulas / Hoy bento | ≠ MATIZ |
| Wizard + comparador de fincas | ≠ ZAGUÁN |
| Lookbook editorial | ≠ MARGEN |
| App nativa | Fuera de stack daily |
| Hero 2-col + 3 cards | AP-12 |
6. Orden de ataque si hay continuidad de código
- Contratos 05–06 + seed 05 + smoke 13 (build paralelo)
- Web paridad UI-00…11
- Ticket público mínimo + rate limit (L+1)
- Cancel CONSERJE si hay campo
- Evaluar brief L3 (no parche silencioso)
16-interaction-specs.md
16 — Especificación de interacción — TEMPLE
1. Convenciones
| Token | Valor |
|---|---|
| Duración corta | 120–160ms |
| Easing | ease-out |
| Reduced motion | 0ms |
| Target | ≥44×44 (slots kiosk ≥56 preferible) |
| Pending | control disabled + aria-busy |
Loading (skeleton de UI-10) y slots mobile (UI-11) viven en este doc junto a los gestos; el inventario Paper ya reserva UI-10 y UI-11. [DECISIÓN]
2. Kiosk home (UI-01) + mobile (UI-02) · H-KIOSK
| Gesto | Resultado |
|---|---|
| Primera carga | Loading: 3 tiles panel; aria-busy |
| 200 con 3 | 3 salas. Lead: eslogan. 3 datos por tile |
| 200 con 0 | UI-08 empty |
| Error 5xx / red | UI-09 + Reintentar (repite GET rooms) |
| Tap tile | /sala/:slug |
| Tap Turno (ghost) | /login o /turno si hay token |
| Hover tile desktop | Rule 1px cream. Sin lift |
AC: nombre, lead y 3 datos visibles sin hover. 3 salas en el fold (AP-21). Cero botones Entradas / Concierto / Crear cuenta.
El aviso «TEMPLE no vende entradas» es texto, no un CTA de compra. [DECISIÓN]
390: mismas 3 salas apiladas. No carousel. [DECISIÓN]
3. Rejilla de horas (UI-03) + mobile (UI-11)
| Gesto | Resultado |
|---|---|
| Primera carga | Loading: 5 celdas; aria-busy |
| 200 | 5 bloques free/taken |
| 0 libres | UI-08 + ← Salas |
| Error | UI-09 + Reintentar |
| Tap slot free | Selecciona; abre confirmar (UI-04) |
| Tap slot taken | No POST; no abre confirmar |
| Tap ← Salas | / |
AC: Libre / Cogida en texto. Taken sin nombre de banda. 5 bloques en orden.
390: 1 o 2 columnas de bloques, no 5 aplastadas. [DECISIÓN]
4. Confirmar (UI-04)
| Campo | Interacción |
|---|---|
| bandName | text · autocomplete organization / name |
| Gesto | Resultado |
|---|---|
| Coger hora | POST; pending; no navegar si inválido |
| Submit inválido | Foco al campo error; no POST |
| Error red | Botón Reintentar; no limpia el nombre |
| 409 | Banner «Esa hora ya está cogida.»; cierra confirmar; refresca GET :slug |
| Doble tap | Ignorado mientras pending |
| 201 | Navega /ok/:code con state (sala, slot, banda, code) |
| Cancelar / Escape | Vuelve a rejilla |
Submit deshabilitado si nombre < 2 o no hay slot.
[DECISIÓN] Un solo botón primario: Coger hora. No existe «Comprar entrada» ni «Pagar ahora».
390: hoja inferior, CTA full-width h-44. Teclado iOS: scroll-margin en el campo. Safe-area inferior.
Desktop 1440: panel junto a la rejilla o debajo, CTA min 200px no full-bleed de viewport.
5. Success / ticket (UI-05)
| Gesto | Resultado |
|---|---|
| CTA primario | Coger otra / |
| Copy | Visible «Hora cogida no es concierto» + código + «no vende entradas» + «sala ≠ escenario» + «ensayar no es actuar» |
| Recarga | Código de URL + copy; sin hidratar GET JWT |
Sin confetti. Sin público. Sin «cobrar». Sin escenario que se ilumina.
6. Login (UI-06)
| Gesto | Resultado |
|---|---|
| Submit | POST login; pending en botón |
| 200 | Guarda token + user; navega next sanitizado o /turno |
| 401 | Texto bajo el form; password no se limpia |
| Enter | Submit |
| Volver al kiosk | / |
| Primera carga | Form visible; no skeleton de marca |
next permitido: paths que empiezan por / y no // ni http. Allowlist: /turno.
Login no muestra matriz.
7. Turno horario (UI-07)
| Gesto | Resultado |
|---|---|
| Primera carga | Loading: matriz 5×3; aria-busy |
| 200 | celdas con banda o Libre |
| 0 horas | UI-08 |
| Error | UI-09 + Reintentar |
| Tap celda | Nada Must v1 (no hay ficha). Could L+1: detalle |
| Hover desktop | Rule 1px cream; no elevación |
| Drag-and-drop | No |
| Tap Salir | Limpia storage → /login |
AC: banda o Libre visibles sin hover. Cero botones Entradas / 112 / Recibido.
8. Empty (UI-08) · Error (UI-09) · Loading (UI-10)
| Estado | Interacción |
|---|---|
| Empty kiosk | Titular Fraunces 28 + 1 línea |
| Empty slots | Titular + 1 línea + ← Salas |
| Empty turno | Titular + 1 línea |
| Error | Banner + Reintentar; foco al banner; no pierde form |
| Loading kiosk | 3 tiles panel |
| Loading slots | 5 celdas |
| Loading turno | 5×3 celdas |
| 409 | Banner jewel + refresh rejilla |
9. Cabecera S-MIN
| Gesto | Resultado |
|---|---|
| Tap wordmark (público) | / |
| Tap wordmark (auth) | /turno |
| Tap Turno (kiosk) | /login o /turno |
| Tap Salir | Logout |
| Scroll | Cabecera no hide-on-scroll v1 |
10. Motion
| Superficie | Spec |
|---|---|
| Cambio de ruta | Fade 160ms (off si reduced-motion) |
| Tiles | Fade 160ms, stagger ≤30ms (off si reduced-motion) |
| Slot selected | Filete amber 120ms |
| Skeletons | Estáticos o pulso 1.2s opacity 0.6–1; off si reduced-motion |
Prohibido: scroll-jacking, page transitions de 400ms, parallax de escenario, neón parpadeante, público que aplaude al coger, confetti de «entrada».
11. Criterios de aceptación de interacción
- Un músico en 390px llega de abrir
/a ver un código en ≤ 3 taps útiles (sala → hora → Coger). - Ningún submit permite doble POST.
- Reduced-motion elimina stagger y slide.
- La home no es hero 2-col (AP-12).
- En 390 las 3 salas son visibles sin carousel de marca (AP-21).
/no presenta ningún control de cuenta, entradas o kanban.- El loading de kiosk es skeleton de 3 tiles, no un logo de concierto.
- El ticket muestra «hora ≠ concierto» y «no vende entradas» sin scroll en desktop.
- Lola en 1440 lee Marta Chen en Sala 1 16–18 sin abrir una ficha.
- Un 409 refresca la rejilla y no navega a
/ok. - Manos en el pasillo: cero gestos que exijan hover o swipe horizontal como único camino.
- Confirmación Escape / cancelar no POST.
17-prototype-map.md
17 — Mapa de prototipo — TEMPLE
Paper no es clicable vía MCP. El prototipo vivo es la app Angular.
Los artboards de Paper se construyen en paralelo; esta tabla es el contrato de paridad.
| Ruta | Paper | Rol |
|---|---|---|
/ | UI-01, UI-02, UI-08, UI-09, UI-10 | BANDA / Guest |
/sala/:slug | UI-03, UI-04, UI-11 | BANDA / Guest |
/ok/:code | UI-05 | BANDA / Guest |
/login | UI-06 | CONSERJE |
/turno | UI-07, UI-08, UI-09, UI-10 | CONSERJE |
Proceso: UX-00…UX-11. Tokens: UI-00.
Empty, error y loading se prototipan como estados / variantes de UI-01 / UI-03 / UI-07 además de sus boards propios. Ver doc 16.
Recorrido demo (guión)
- Abrir
/sin token — kiosk público. Leer eslogan La hora, no el concierto. Leer 3 salas (Batería, Combo, Seca) con lead + 3 datos. - Tocar Sala 2 Combo. Ver rejilla: 10–12 / 12–14 / 16–18 cogidas; 18–20 y 20–22 libres. Sin nombres de otras bandas.
- Tocar 18–20. Confirmar: nombre Los Yesos. Leer «Hora cogida no es concierto» y «se paga en ventanilla».
- Coger hora →
/ok/TM-XXXX— «Hora cogida no es concierto. TEMPLE no vende entradas.» «Sala ≠ escenario. Ensayar no es actuar.» - Ghost Turno →
/login. Entrarlola@temple.nave/password123. /turno— horario 5×3. Sala 1 16–18 Marta Chen. Sala 2 18–20 Los Yesos (tras el POST).- Comprobar que no hay botón Entradas, 112-como-envío ni columnas Recibido / En curso.
- Viewport 390: kiosk 3 salas apiladas; rejilla; turno apilado por sala.
- Salir →
/login./sigue siendo el kiosk. - (Opcional) POST otra vez Combo 18–20 → 409.
Estados en el mismo prototipo
| Estado | Cómo provocarlo |
|---|---|
| Empty kiosk | 0 filas en rooms (entorno de test) |
| Empty slots | 0 free en esa sala |
| Error | API caída / 5xx |
| Loading | throttle de red en GET /rooms o /turno |
| 404 sala | /sala/palco |
| 409 | segundo POST al mismo slot |
| 401 turno | /turno sin token → login |
| Kiosk 390 | 390 × 844 en / |
| Kiosk 1440 | 1440 × 900 / (UI-01) |
| Slots 390 | 390 × 844 /sala/combo (UI-11) |
| Ticket recargado | F5 en /ok/TM-2109 · código + copy, sin ficha |
Fuera del prototipo clicable
- Paper artboards son estáticos.
- Llaves físicas y cobro en ventanilla (fuera).
- 112 / taquilla / Conciergo.
- Chat / kanban.
- Cuenta de banda.
- Calendario semanal.
- El dominio de un día anterior no forma parte del prototipo TEMPLE: si aparece chat, mesa o kanban, es desalineación.
18-completeness-audit.md
18 — Auditoría de completitud — TEMPLE (2026-08-21)
1. Alcance auditado
Vertical slice L2: quiosco de horas de ensayo + tablero CONSERJE JWT (horario de ocupación, no kanban), con docs, referencia Paper, contratos Angular + Nest + Neon.
Este encargo cubre la suite documental. El day brief y el paper-reference no se han sobrescrito. El código se escribe en paralelo (/Users/cristian/orca/temple-app).
2. Checklist CRON / ALS-2
| Requisito | Estado | Evidencia |
|---|---|---|
| Diversidad sector/tipo/nivel | OK | Música ensayo L2; no admin pública; no belleza; no L1 consecutivo |
| Terna S/H/F 0 códigos = N−1 · ≥2 vs N−2 | OK | S-MIN · H-KIOSK · F-BOOK vs PREGÓN S-SIDE · H-CHAT · F-KAN |
| Day brief + anti-patrones | OK | docs/00-day-brief.md (no sobrescrito) |
| Paper ≥12 UX + ≥10 UI | OK | UX-count 12 · UI-count 12 · file 01M0HJ2Z7NJSYC0FDMWYSSQBG3 |
| Docs 00–20 | OK | suite en docs/ + executive + README |
| JWT CONSERJE | OK | Role CONSERJE · D-P1-05 · turno cerrado, kiosk público |
| API + seed + Neon | OK | contratos divine-haze-05909195, port 3021, health temple-api |
| Web tokens | OK | Fraunces + Atkinson Hyperlegible · paleta vehicle dashboard |
| Kiosk-first (no AP-12 / AP-21) | OK | UI-01 / docs 03, 07, 08 |
| Hipótesis no fake field | OK | etiquetas en doc 02 |
| Copy ×4 irrenunciable | OK | docs 01, 09, 16 |
| Ground G-INK | OK | #12110F · no G-FOG / G-CHAPEL / G-CONCRETE |
| No Conciergo / no 112 / no kanban / no chat | OK | docs 01, 03, 09 |
3. Cobertura funcional
| Feature brief | Spec | UI Paper | API | Docs |
|---|---|---|---|---|
| Home kiosk 3 salas | Sí | UI-01, UI-02 | GET rooms | 03, 04, 16 |
| Rejilla 2 h hoy | Sí | UI-03, UI-11 | GET rooms/:slug | 04, 05 |
| Confirmar nombre de banda | Sí | UI-04 | POST bookings | 04, 09 |
| Ticket código | Sí | UI-05 | POST 201 | 04, 09 |
| Login CONSERJE | Sí | UI-06 | POST login | 04, 06 |
| Turno horario | Sí | UI-07 | GET turno | 03, 04, 16 |
| Empty | Sí | UI-08 | 200 [] | 16 |
| Error | Sí | UI-09 | 5xx/red/409 | 16 |
| Loading | Sí | UI-10 | pending | 16, 17 |
| Kiosk / slots mobile | Sí | UI-02, UI-11 | misma API | 04, 16 |
| Design system | Sí | UI-00 | — | 08 |
| Seed 1 + 3 + 8 (8/15) | Sí | — | seed | 05 |
| Health temple-api | Sí | — | GET health | 05, 06, 20 |
| Unique slot 409 | Sí | UI-09 | POST 409 | 05, 13 |
4. Cobertura Paper (literales)
| ID | Nombre | En 00-paper-reference |
|---|---|---|
| UX-00 | Cover | Sí |
| UX-01 | Stakeholders | Sí |
| UX-02 | Personas | Sí |
| UX-03 | JTBD | Sí |
| UX-04 | Stories | Sí |
| UX-05 | Journey | Sí |
| UX-06 | Blueprint | Sí |
| UX-07 | Site map | Sí |
| UX-08 | Flujos | Sí |
| UX-09 | Datos+permisos | Sí |
| UX-10 | Métricas | Sí |
| UX-11 | Research | Sí |
| UI-00 | Tokens | Sí |
| UI-01 | Kiosk home | Sí |
| UI-02 | Kiosk mobile | Sí |
| UI-03 | Slots | Sí |
| UI-04 | Confirm | Sí |
| UI-05 | Success | Sí |
| UI-06 | Login | Sí |
| UI-07 | Turno | Sí |
| UI-08 | Empty | Sí |
| UI-09 | Error | Sí |
| UI-10 | Loading | Sí |
| UI-11 | Slots mobile | Sí |
[COMPROBADO] UX-count: 12 y UI-count: 12 literales en docs/00-paper-reference.md (no sobrescrito). Gate check-paper-reference.mjs aplica.
5. Rúbrica de calidad (auto SCORE orientativo · docs)
| Eje | Score 1–5 | Comentario |
|---|---|---|
| Diversidad | 5 | Kiosk+horas música vs chat+kanban PREGÓN, PWA oficio MATIZ y wizard ZAGUÁN; L2 no L1 |
| Craft visual (spec) | 4–5 | Vehicle dashboard + Fraunces/Atkinson + fotos de sala documentadas |
| Densidad UX docs | 5 | Suite L2: tablas, AC, etiquetas S/H/D |
| Unicidad estructura | 5 | R-HY · S-MIN · H-KIOSK · F-BOOK · 0 códigos = N−1 |
| Paper counts | 5 | 12 UX + 12 UI en paper-reference |
| Honestidad de research | 5 | Sin entrevistas inventadas; personas como constructo |
| Contrato de build | 5 | rooms + bookings + JWT CONSERJE · :3021 · temple-api |
6. Huecos conscientes (no deuda del L2 del día)
| Hueco | Tratamiento |
|---|---|
| Código Angular/Nest en paralelo | Doc 20 = contrato; no se finge un leftover como estado |
| Instrumentación analytics | Modelo (doc 12); no cifras inventadas |
| Campo real con músicos | Plan en doc 02 §10; no ejecutado |
| Cancel / grey de pasados / ticket hidratado | L+1 (docs 15, 19) |
7. Cierre documental
La suite ALS de TEMPLE (README + executive + docs 01–20) cubre el vertical slice L2 del brief. docs/00-day-brief.md y docs/00-paper-reference.md permanecen intactos.
19-backlog-completo.md
19 — Backlog completo — TEMPLE
Inventario de ítems. Los del alcance L2 documental del día están Done.
El resto es opcional / siguiente nivel, no deuda oculta del cierre.
1. Done — L2 case documental (2026-08-21)
| ID | Ítem | Capa |
|---|---|---|
| D01 | Definición producto TEMPLE + eslogan | Docs |
| D02 | Day brief diversidad música ensayo L2 | Docs (preexistente, no pisado) |
| D03 | Terna R-HY · S-MIN · H-KIOSK · F-BOOK | Docs |
| D04 | Personas Iván Mora / Lola Rivas / Marta Chen | Docs + Paper ref |
| D05 | JTBD + stories Must | Docs |
| D06 | IA kiosk-first + chrome S-MIN | Docs |
| D07 | Flujos F0–F9 + AC | Docs |
| D08 | Modelo users / rooms / bookings | Docs |
| D09 | Contratos API :3021 · health temple-api | Docs |
| D10 | Auth JWT CONSERJE · POST bookings público | Docs |
| D11 | Unique slot + 409 · 401 turno | Docs |
| D12 | Kiosk 3 salas + rejilla 5 bloques + confirmar | Docs |
| D13 | Microcopy ×4 (concierto / escenario / entradas / actuar) | Docs |
| D14 | North star % bloques sin WhatsApp | Docs |
| D15 | Tokens vehicle dashboard + Fraunces / Atkinson | Docs |
| D16 | Paper UX-00…11 + UI-00…11 | Docs |
| D17 | Suite docs 00–20 + README + executive | Docs |
| D18 | Seed 1 CONSERJE + 3 salas + 8 horas 8/15 | Docs |
| D19 | Assets listados (hero + 3 salas) | README |
| D20 | QA smoke + S1–S30 | Docs |
| D21 | Neon divine-haze-05909195 | Docs |
| D22 | Kiosk 390/1440 + turno horario especificados | Docs |
| D23 | Ground G-INK #12110F | Docs |
| D24 | Rutas reales solo las 5 del encargo | Docs |
| D25 | Kiosk no filtra bandName ajeno | Docs |
Los must-have del brief (kiosk, horas, confirmar, ticket, login, turno, empty/error/loading, mobile, ≥12 UX + ≥10 UI) están dentro de D01–D25, no como leftover.
2. Backlog L2 implementación (repo temple-app)
Alineación de código al contrato ya cerrado. Se escribe en paralelo. No es alcance documental pendiente.
| ID | Ítem | Prioridad | Notas |
|---|---|---|---|
| I01 | Implementar apps/api + apps/web al contrato TEMPLE | P0 | rooms + bookings + JWT CONSERJE |
| I02 | Schema users / rooms / bookings | P0 | UNIQUE (room_id, day, slot) |
| I03 | Seed Lola + 3 rooms + 8 bookings 8/15 | P0 | |
| I04 | GET rooms público · GET :slug sin bandName | P0 | |
| I05 | POST bookings público + 409 | P0 | status CONFIRMED al crear |
| I06 | POST login JWT | P0 | lola@temple.nave |
| I07 | GET health service: "temple-api" | P0 | puerto 3021 |
| I08 | GET /api/turno JWT | P0 | 401 sin token |
| I09 | Auth guard Angular solo /turno | P0 | / /sala/:slug /ok/:code públicos |
| I10 | Kiosk / slots / ok / login / turno | P0 | |
| I11 | Tokens Tailwind ink/panel/cream/amber + fotos | P0 | Fraunces + Atkinson |
| I12 | Smoke curl + build | P0 | D-P1-06 |
3. Backlog L+1 (polish)
| ID | Ítem | Prioridad | Notas |
|---|---|---|---|
| B01 | Ticket público mínimo { code, roomName, slot } | P1 | no listar otras horas |
| B02 | Cancel CONSERJE | P2 | no self-service |
| B03 | Rate limit login + POST bookings | P1 | anti stuffing / spam |
| B04 | Playwright smoke | P1 | CI |
| B05 | Skeleton UI-10 en código | P2 | |
| B06 | GET /api/me | P2 | |
| B07 | Grey de bloques pasados | P3 | demo v1 no greyea |
| B08 | API URL por environment | P1 | deploy |
| B09 | Página 404 amigable | P3 | |
| B10 | Sessions invalidables | P2 | |
| B11 | ?slot= deep link | P3 |
4. Backlog L3 (requiere brief nuevo)
| ID | Ítem | Dependencia |
|---|---|---|
| C01 | Multi-conserje / multi-nave | users + membership |
| C02 | Cuenta BANDA + «mis horas» | authz · rompe H3 |
| C03 | Calendario semanal | D13 se rompe · brief nuevo |
| C04 | Pago / taquilla / entradas | microcopy se rompe |
| C05 | Chat / kanban / 112 | terna se rompe |
5. Explícitamente no-backlog
Entradas, Conciergo, escenario, 112, chat, kanban, rider, TPV en kiosk, hero 2-col. Ver docs 01 y 15.
20-implementation.md
20 — Implementación — TEMPLE
1. Resumen ejecutivo técnico
| Campo | Valor |
|---|---|
| App path | /Users/cristian/orca/temple-app |
| API | NestJS · puerto 3021 · prefijo /api |
| Web | Angular standalone · puerto 4200 |
| Package | apps independientes (npm --prefix o pnpm --filter) |
| DB | Neon PostgreSQL · project divine-haze-05909195 |
| Tablas | users, rooms, bookings (+ sessions Should) |
| Auth | JWT Bearer · role CONSERJE (turno); kiosk y POST bookings públicos |
| Dominio | User, Room, Booking |
| Fecha | 2026-08-21 |
| GitHub | https://github.com/Criscode2022/temple-app |
Este documento es la especificación de build alineada al case. No sustituye al código: si el repo diverge, gana el contrato de docs 05 + este archivo tras actualizar ambos.
El código se escribe en paralelo a esta suite. Contrato: rooms + bookings + JWT CONSERJE. Puerto 3021. Health temple-api.
[COMPROBADO] Path, puerto, Neon, Paper y GitHub salen del encargo.
2. Cómo arrancar
cd /Users/cristian/orca/temple-app
# instalar dependencias por app (no npm workspaces)
# apps/api/.env
# DATABASE_URL= # Neon divine-haze-05909195
# JWT_SECRET=
# PORT=3021
# schema + seed
# api → http://localhost:3021
# web → http://localhost:4200
Credenciales
| Rol | Password | |
|---|---|---|
| CONSERJE | lola@temple.nave | password123 |
Banda / batería: sin cuenta. Cogen hora en /.
3. Schema
Al boot o vía migrate:
CREATE TABLE/ migrate deusers,rooms,bookings(doc 05). Opcionalsessions.- Índices:
rooms(slug),bookings(code),bookings(day, slot),users(email). UNIQUE(room_id, day, slot). - Seed idempotente:
- upsert CONSERJE
lola@temple.nave(bcrypt depassword123) - upsert
roomsporslug(bateria,combo,seca) - upsert
bookingsporcode(TM-2101…TM-2108) conday= hoy Europe/Madrid (o fecha demo documentada)
- upsert CONSERJE
- Dominio: solo rooms + bookings + users. [DECISIÓN]
No borrar horas nuevas de Iván en cada boot si ya existen filas distintas al seed.
Generador de código: SELECT max(code) numérico + 1, formateado TM- + 4 dígitos (padding). Seed máximo 2108 → siguiente POST = TM-2109. Si se agota 9999, L+1 amplia a 5 dígitos; no es Must.
Tablas (recordatorio)
| Tabla | Contenido |
|---|---|
users | CONSERJE Lola |
rooms | 3 salas |
bookings | 8 horas 8/15 |
sessions | Should: sid + token_hash + expires_at |
4. Módulos API a implementar
Auth
POST /api/auth/login- Valida email/password; compara bcrypt; emite JWT con
sub, email, role. - Guard JWT +
role === CONSERJEprotege GET turno. - Públicos: health, rooms, rooms/:slug, POST bookings, login.
Oficio
| Método | Ruta | Auth | Notas |
|---|---|---|---|
| GET | /api/health | No | { ok: true, service: "temple-api" } |
| GET | /api/rooms | No | sort_order asc + freeToday / slotsToday |
| GET | /api/rooms/:slug | No | slots free / taken sin bandName |
| POST | /api/bookings | No | crea CONFIRMED + code; day = hoy; 409 si unique |
| GET | /api/turno | JWT | matriz con bandName |
Health (referencia de implementación)
HealthService.name = 'temple-api'
main.ts PORT default 3021
Turno (referencia)
slots = ['10-12','12-14','16-18','18-20','20-22']
rooms = ORDER BY sort_order
bookings WHERE day = today AND status = 'CONFIRMED'
para cada room × slot:
si hay booking → { status: 'taken', bandName, code }
si no → { status: 'free', bandName: null, code: null }
return { day, naveName, slots, rooms: [{ slug, name, cells }] }
JSON camelCase: bandName, roomSlug, sizeM2, freeToday, naveName, createdAt.
SQL: band_name, room_id, size_m2, nave_name, created_at.
POST no cobra, no emite entrada, no llama al 112, no mueve kanban.
Módulos de dominio: rooms/, bookings/, auth/, health.
5. Frontend a implementar
| Página | Ruta | Responsabilidad |
|---|---|---|
| KioskPage | / | GET rooms, 3 tiles, empty/loading/error |
| SlotsPage | /sala/:slug | GET :slug, rejilla, confirmar, POST bookings, 409 |
| OkPage | /ok/:code | código + copy; state opcional; sin GET JWT |
| LoginPage | /login | form → login → turno |
| TurnoPage | /turno | GET turno, matriz horario, empty/loading/error |
Shell autenticada: cabecera S-MIN (wordmark, hoy, Lola, Salir). Kiosk, sala y ok: sin rail. Login: sin matriz.
ApiService centraliza base URL http://localhost:3021/api, token storage (temple_token, temple_user), métodos tipados (Room, RoomDetail, Slot, Booking, TurnoBoard, User).
AuthGuard solo en /turno. Interceptor Authorization: Bearer cuando hay token (no bloquea POST público).
index.html: título TEMPLE — La hora, no el concierto. Fuentes Fraunces + Atkinson Hyperlegible. Body bg-ink text-cream.
proxy.conf.json y environment*.ts: 3021.
Rutas de otros productos (/mesa, /chat, /hoy, /fichas) fuera.
6. Decisiones de implementación
| Decisión | Razón |
|---|---|
| Puerto API 3021 | Evitar colisión con PREGÓN 3020 |
Tablas rooms / bookings | Dominio de ensayo, no chat ni fórmulas |
Role CONSERJE | Encargo |
Health temple-api | Encargo |
| Kiosk público + turno JWT | S2 / H3 / D-P1-05 |
| JSON camelCase | Convenio web serie daily |
| POST bookings público | Encargo; banda sin cuenta |
Success /ok/:code sin GET | D9 enumeración |
| Slots públicos sin bandName | D9 pasillo |
| UNIQUE + 409 | Dos bandas no caben |
| day = hoy servidor | D13; el cliente no elige mañana |
| Apps independientes | AP-06 |
| Home no usa hero 2-col | AP-12 / H-KIOSK |
| Turno = horario | No F-KAN |
| Pago fuera | S4 |
7. Variables de entorno
| Variable | Servicio | Descripción |
|---|---|---|
DATABASE_URL | API | Neon divine-haze-05909195 |
JWT_SECRET | API | Firma tokens |
PORT | API | opcional, 3021 |
JWT_EXPIRES | API | opcional, default 12h |
Web: URL de API en ApiService (default localhost:3021).
8. Smoke de implementación (mínimo)
- Schema OK (tablas
users,rooms,bookingsexisten). GET /api/health200{ ok: true, service: "temple-api" }.GET /api/rooms200 · 3 salas · slugs bateria/combo/seca.GET /api/rooms/combo200 · 5 slots · sinbandName.POST /api/auth/login200 +accessToken+role=CONSERJE.GET /api/turnoBearer: 8 taken / 7 free, codes TM-2101…2108, Marta Chen en bateria 16-18.GET /api/turnosin token 401.POST /api/bookings{ "roomSlug":"combo","slot":"18-20","bandName":"Los Yesos" }sin token 201status=CONFIRMED.- Segundo POST al mismo slot 409.
- Web: 3 salas dominantes, horario en turno, disclaimers ×4, fotos 4:3, fuentes Fraunces/Atkinson.
9. Estructura de ficheros clave (objetivo)
temple-app/
├── package.json
├── apps/api/
│ ├── src/
│ │ ├── main.ts # PORT 3021
│ │ ├── app.module.ts
│ │ ├── auth/
│ │ ├── rooms/
│ │ ├── bookings/
│ │ └── health.controller.ts # service: temple-api
│ └── .env.example
├── apps/web/
│ ├── proxy.conf.json # :3021
│ ├── tailwind.config.js # ink / panel / cream / amber / …
│ └── src/app/
│ ├── app.routes.ts
│ ├── core/api.service.ts
│ ├── shell/turno-header.component.ts
│ └── pages/
│ ├── kiosk/
│ ├── slots/
│ ├── ok/
│ ├── login/
│ └── turno/
└── README.md
Nombres de fichero orientativos; el contrato es de rutas y tablas, no de filenames exactos.
10. Seed — checklist de implementación
| # | Check |
|---|---|
| 1 | User Lola Rivas / lola@temple.nave / password bcrypt de password123 / role CONSERJE |
| 2 | 3 rooms bateria combo seca con covers y size_m2 |
| 3 | 8 bookings TM-2101…2108 con slots y bandas de doc 05 |
| 4 | Conteos 8 CONFIRMED · 7 libres |
| 5 | TM-2104 = Marta Chen · bateria · 16-18 |
| 6 | Combo 18-20 libre para el POST de Los Yesos |
| 7 | Idempotencia: upsert por email / room slug / booking code |
| 8 | day coherente con «hoy» del turno |
11. Alineación case ↔ app
| Doc | Evidencia esperada en código |
|---|---|
| 05 data model | columnas y enums |
| 03–04 IA/flows | routes + controllers |
| 08 DS | tailwind colors + fontFamily Fraunces/Atkinson |
| 09 content | strings en templates (microcopy ×4) |
| 00 paper | URLs en README case |
| 11 security | Guard en turno; POST bookings público; 401 GET turno; slots sin bandName |
12. Estado del build (paralelo)
Esta suite no documenta un leftover de otro producto como estado actual del repo. El contrato vigente es:
| Pieza | Contrato |
|---|---|
| Path | /Users/cristian/orca/temple-app |
| Health | temple-api · puerto 3021 |
| Tablas | users · rooms · bookings |
| Role | CONSERJE JWT |
| Rutas | / /sala/:slug /ok/:code /login /turno |
| Tokens | ink / panel / cream / amber / mute / jewel · Fraunces + Atkinson |
Smoke objetivo: GET /api/health, GET /api/rooms, GET /api/rooms/:slug, POST /api/bookings, login lola@temple.nave, GET /api/turno con JWT, ng build.
13. Notas de cierre técnico
- El case L2 documental está cerrado: docs + Paper 12 UX / 12 UI + contrato de vertical slice.
- Must-have del brief tienen AC y smoke.
- El código se escribe en paralelo bajo este contrato.
- Mejoras (ticket hidratado, e2e, cancel) viven en backlog L+1.