On this page 00 — Day brief · 2026-08-21 · TEMPLE 0%

00-day-brief.md

00 — Day brief · 2026-08-21 · TEMPLE

Decisiones ALS-2 BRIEF

CampoValor
Fecha2026-08-21
NombreTEMPLE
ComplejidadNivel 2 (no L1 consecutivo tras PREGÓN)
SectorMúsica / local de ensayo de barrio (nave Carabanchel)
TipoQuiosco de horas + tablero CONSERJE JWT (no entradas, no concierto)
PlataformaWeb kiosk-first (pantalla en el pasillo · mesa conserje desktop)
RegistroR-HY — portada de local clásica + herramienta de horas (no 2× R-IN)
ShellS-MIN — casi sin nav; el quiosco es una acción
HomeH-KIOSK — tres salas enormes; no hero 2-col, no chat, no bento
FlujoF-BOOK — coger un bloque de 2 h; no kanban, no editor
Por qué no PREGÓNNo S-SIDE / H-CHAT / F-KAN; no admin pública
Por qué no MATIZNo S-BOTTOM / H-BENTO / F-EDIT; no belleza
Por qué no ConciergoEnsayo ≠ 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:
    • #12110F instrument black (ground)
    • #1E1C18 panel
    • #F4EBD0 crema de dial
    • #E8A317 ámbar LED / gaffer
    • #8C8474 mute
    • #C23B22 joya 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

  1. Home kiosk: 3 salas a pantalla completa (lead + 3 datos)
  2. Rejilla de horas (bloques de 2 h, hoy)
  3. Confirmar con nombre de banda (sin cuenta)
  4. Ticket (hora cogida ≠ concierto)
  5. Login JWT CONSERJE
  6. Tablero de ocupación de hoy (horario, no kanban)
  7. Empty / error / loading / mobile kiosk
  8. ≥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

IDSeñal
H1Un quiosco de 3 salas reduce “¿está libre la 2?” por WhatsApp
H2Separar hora de concierto evita la expectativa de entradas
H3Bloques fijos de 2 h bastan; el músico no necesita login

00-paper-reference.md

Paper reference · TEMPLE

URLhttps://app.paper.design/file/01M0HJ2Z7NJSYC0FDMWYSSQBG3
File ID01M0HJ2Z7NJSYC0FDMWYSSQBG3

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)

IDNombreContenido
UX-00CoverTEMPLE · «La hora, no el concierto.» · R-HY · S-MIN · H-KIOSK · F-BOOK · L2 música ensayo · vehicle dashboard · 2026-08-21
UX-01StakeholdersBANDA (Iván), CONSERJE (Lola), nave, Conciergo fuera de alcance
UX-02PersonasIván Mora 29 · Lola Rivas 47 · Marta Chen 34 (batería)
UX-03JTBDJob «coger Sala 2 dos horas sin preguntar por WhatsApp»
UX-04StoriesMust: kiosk, horas, ticket, login, turno, estados
UX-05JourneyLlega con la funda → toca sala → hora → ticket → (Lola) ve ocupación
UX-06BlueprintFrontstage kiosk · backstage llaves · Nest/Neon/JWT
UX-07Site mapPúblico / kiosk · /ok/:code · /login · /turno
UX-08FlujosF-BOOK público; F-TURNO CONSERJE
UX-09DatosUser CONSERJE · Room · Booking; JWT en turno
UX-10MétricasNorth star % bloques ocupados sin WhatsApp
UX-11ResearchComprobado / supuesto / hipótesis / decisión

UI producto (prefijo UI- · mínimo 10)

IDNombreFlujo
UI-00TokensDS dashboard: ink, panel, cream, amber, mute, jewel
UI-01Kiosk homeH-KIOSK 1440: 3 salas enormes. Lead + 3 datos
UI-02Kiosk mobile390: mismas 3 salas
UI-03SlotsBloques 2 h de hoy
UI-04ConfirmNombre de banda
UI-05SuccessTicket. Hora ≠ concierto
UI-06LoginJWT CONSERJE
UI-07TurnoOcupación de hoy (horario, no kanban)
UI-08EmptySin horas / sin salas
UI-09ErrorRed
UI-10LoadingSkeletons
UI-11Slots mobileRejilla en 390

Mapeo Paper → Angular

ArtboardRutaComponente
UI-01 Kiosk/KioskPage
UI-03 Slots/sala/:slugSlotsPage
UI-05 Success/ok/:codeOkPage
UI-06 Login/loginLoginPage
UI-07 Turno/turnoTurnoPage

01-project-definition.md

01 — Definición de proyecto — TEMPLE

1. Identidad

CampoValor
NombreTEMPLE
SignificadoTemple 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 fraseQuiosco de horas + tablero CONSERJE JWT (horario de ocupación de hoy).
SectorMúsica / local de ensayo de barrio (nave Carabanchel)
TipoWeb L2 — kiosk-first + rejilla de 2 h + ticket + turno — Nivel 2, herramienta de horas usable
PlataformaWeb kiosk-first (pantalla en el pasillo · mesa conserje desktop)
Mercado demoEspaña · Madrid · Carabanchel · Paseo de Yeserías (una nave, no una red)
Idiomaes-ES
Fecha caso2026-08-21
TernaR-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

ProblemaQuién lo sufreEfecto
«¿Está libre la 2?» por WhatsAppBANDA (Iván)Espera, funda en el suelo, llega y está cogida
Hora se lee como conciertoBANDA + naveEsperan entrada, aforo, taquilla
Sala se lee como escenarioBANDA + públicoLuces, palco, «tocamos esta noche»
El kiosk se lee como 112CONSERJE + naveUrgencia vital en un canal de horas
El tablero se lee como kanbanCONSERJE (Lola)Esperan Recibido / En curso / Cerrado
La dueña pide TPV y entradas el día 1NaveEl 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

IDHipótesisSeñal de validación (futura)
H1Un quiosco de 3 salas reduce “¿está libre la 2?” por WhatsApp% de visitas a / que terminan en POST con código
H2Separar hora de concierto evita la expectativa de entradas↓ «pensé que era una entrada»; copy visible en ticket
H3Bloques fijos de 2 h bastan; el músico no necesita login0 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

ParaValor
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 TEMPLEUn quiosco mínimo: salas + horas + turno, sin Conciergo y sin 112.

No es TEMPLE

ExcluidoPor qué
Entradas / taquilla / aforoHora cogida ≠ concierto
Escenario / palco / luces de conciertoSala ≠ escenario
Conciergo / ticketingTEMPLE no vende entradas
«Ya estáis tocando» al coger horaEnsayar no es actuar
112 / urgencia vitalTEMPLE no es 112
Chat de incidencias / kanbanEso fue PREGÓN (H-CHAT / F-KAN)
Cuaderno de fórmulas / Hoy bentoEso fue MATIZ (H-BENTO / F-EDIT)
Wizard de fincas + comparadorEso fue ZAGUÁN (H-WIZARD / F-CMP)
Lookbook / masthead editorialEso 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 / pasarelaS4: se paga en ventanilla
Backline extra / riderS4
App de 40 salas y calendario semanalL2 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

RolObjetivo medible en demo
BANDAVer 3 salas, coger un bloque y ver el código en < 60 s, sin cuenta
CONSERJEEntrar a turno, ver horario 8/15, leer Marta Chen en Sala 1 16–18 en < 45 s
BATERÍAMisma 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ónAnónimo (banda)CONSERJETaquilla / 112
Ver kiosk / salasNo hay cuenta
POST horaSí (no es el job)No
Ver ticket /ok/:code (código en URL)
Ver turnoNo (401 / redirect)No
GET /api/turno401
Ver nombre de otras bandas en kioskNo (solo libre / cogida)Sí (horario)
Vender entradaNo (no existe)NoFuera
Llamar al 112Copy: fueraCopy: fueraEl 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)

TipoMétricaDefinición
North Star% de bloques ocupados sin WhatsAppOficio de pasillo, no pageviews
Activación banda1.er POST con codeH1
Integridad de expectativaReclamaciones «¿dónde está mi entrada?» / «¿es el escenario?» / «¿es el 112?»H2 + microcopy
Integridad de authGET /api/turno sin token → 401; POST /api/bookings sin token → 201Kiosk público + turno cerrado
SaludError rate API rooms / bookings4xx/5xx

7. Alcance funcional v1 (L2)

MóduloIncluido
KioskGET /api/rooms · 3 salas enormes (lead + 3 datos)
HorasGET /api/rooms/:slug · bloques de 2 h de hoy
ConfirmarNombre de banda (sin cuenta)
Ticket públicoPOST /api/bookings · { roomSlug, slot, bandName }TM-XXXX CONFIRMED
AuthPOST /api/auth/login → JWT CONSERJE
TurnoGET /api/turno JWT · horario de ocupación de hoy
Estados UIEmpty (0 salas / 0 horas), loading skeleton, error de red, 409 slot cogido
MobileKiosk ~390px · rejilla de horas · targets ≥44px
Seed1 CONSERJE, 3 salas, 8 horas (8/15)
SaludGET /api/health{ ok: true, service: "temple-api" }

8. Criterios de aceptación de producto

  1. / es el kiosk de 3 salas. No pide cuenta. No es un hero 2-col + 3 cards.
  2. 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.
  3. /ok/:code dice explícitamente que hora cogida no es concierto y que TEMPLE no vende entradas.
  4. La UI dice explícitamente que sala no es escenario y que ensayar no es actuar.
  5. Sin token, GET /api/turno responde 401. POST /api/bookings y GET /api/rooms son públicos.
  6. Un POST de hora crea status=CONFIRMED. Coger no emite una entrada.
  7. Una CONSERJE inicia sesión y ve el horario con 8 cogidas / 7 libres en el seed.
  8. El tablero es un horario (filas = bloques, columnas = salas). No es un kanban de 3 columnas.
  9. Fotos reales en las 3 salas seed (assets salas/*).
  10. Bloques visibles: 10–12 · 12–14 · 16–18 · 18–20 · 20–22.
  11. Chrome S-MIN: casi sin nav. Kiosk público sin top-nav de marketing.
  12. Rutas solo las del doc 03. No existen /entradas, /concierto, /112, /mesa, /chat.
  13. GET /api/health devuelve service: "temple-api".
  14. El kiosk no muestra el nombre de otras bandas; el turno sí.

9. Stack y artefactos

CapaDetalle
FrontendAngular + Tailwind · puerto 4200
BackendNestJS · puerto 3021
DBNeon PostgreSQL · project divine-haze-05909195
AuthJWT (CONSERJE)
DiseñoPaper 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

RiesgoImpactoMitigación v1
Expectativa de entrada«¿Dónde está mi ticket de concierto?»Copy «Hora cogida ≠ concierto» · «TEMPLE no vende entradas»
Expectativa de escenarioLuces, palco, públicoCopy «Sala ≠ escenario»
Expectativa de 112Urgencia vital en el kioskCopy «TEMPLE no es 112»
Expectativa de kanbanRecibido / En cursoHorario, no columnas de estado
Pago en kiosk el día 1Alcance L3 disfrazadoS4: ventanilla
Cuenta de bandaRompe S2 / H3Sin signup; nombre libre en el booking
Home percibida como landing de sala de conciertosPérdida de H-KIOSK / AP-12Las 3 salas son la home; no hero 2-col
Confundir con PREGÓN (chat + kanban)Expectativa de parteKiosk de salas; no hilo
Confundir con ConciergoExpectativa de entradasMicrocopy ×4
Double-book del mismo bloqueDos bandas a la misma horaUnique (room, day, slot) · 409
Enumeración de horas por códigoPII de banda en públicoGET turno JWT; /ok/:code no hidrata ficha ajena
0 salasKiosk vacío sin oficioEmpty «Aún no hay salas.»
WhatsApp paraleloH1 no se mideNorth star etiquetada como modelo

11. Glosario

TérminoDefinición en TEMPLE
TempleRecinto de ensayo; el producto, no un concierto
SalaCuarto con moqueta (rooms); no es un escenario
EscenarioSuperficie de concierto; fuera
Hora / bloque / slotTramo fijo de 2 h; 10-1220-22
Hora cogidaPOST 201 + código; no significa concierto
TicketAcuse de hora (TM-XXXX); no es una entrada
EntradaTicket de concierto; fuera. TEMPLE no vende entradas
Quiosco / kioskSuperficie H-KIOSK pública del pasillo
TurnoSuperficie de ocupación de la CONSERJE (horario)
KanbanLenguaje de diseño de otros días; no hay columnas aquí
CONSERJEUsuario autenticado que opera el turno
BANDAAutora/autor de la hora; no tiene fila en users
VentanillaPago fuera de la app (S4)
InkGround #12110F
PanelSuperficie #1E1C18
CreamDial #F4EBD0
AmberLED / gaffer #E8A317
MuteMeta #8C8474
JewelAcento de ampli #C23B22, poco
112Emergencia vital; fuera
ConciergoProducto de entradas; fuera

12. Decisiones de diseño (cierre de brief)

IDDecisiónAlternativa descartada
D1Home = 3 salas enormes (H-KIOSK)Hero 2-col + 3 cards (AP-12) · chat (PREGÓN) · bento (MATIZ) · wizard (ZAGUÁN)
D2Shell mínimo (S-MIN)Rail de estados · bottom tabs · masthead · wizard chrome
D3Registro híbrido vehicle dashboard (R-HY)Escenario+neón (primer instinto; Conciergo) · highlighter PREGÓN
D4Flujo F-BOOK (coger un bloque de 2 h)F-KAN, F-EDIT, F-CMP, F-STORY, F-CHAT
D5Mood vehicle dashboardNocturnal concierto (primer instinto), highlighter, chapel, rusted
D6Un rol autenticado CONSERJEMulti-rol dueña / taquilla / banda / 112
D7Status de hora CONFIRMEDKanban de 3 columnas; HOLD; «en escenario»
D8Banda sin cuentaSignup, seguimiento con login
D9Kiosk no filtra nombres de otras bandasTablero público enumerabile
D10POST público { roomSlug, slot, bandName }Formulario de rider + pago + DNI
D11Ground G-INK #12110FG-FOG, G-CHAPEL, G-CONCRETE, G-GALLERY, G-MOSS
D12Success de ticket en /ok/:codeToast único sin pantalla
D135 bloques fijos de hoy, sin 14–16Calendario semanal; slots de 30 min
D14Turno = horario, no kanbanRecibido / En curso / Cerrado
D15Kiosk público + turno JWT (no auth-first total)Todo cerrado (rompería S2) · todo abierto (rompería turno)
D16Pago en ventanillaPasarela en kiosk
D17Unique (room_id, day, slot)Overbooking «por si acaso»

13. Relación con el día anterior

CaseTernaPor qué TEMPLE no lo copia
PREGÓN (N−1)S-SIDE / H-CHAT / F-KANNo admin pública, no chat, no kanban, no 112
MATIZ (N−2)S-BOTTOM / H-BENTO / F-EDITNo belleza, no PWA de oficio, no editor de gramos
ZAGUÁN (N−3)S-WIZ / H-WIZARD / F-CMPNo inmobiliaria, no wizard, no comparador
MARGEN (N−4)S-TOP / H-GALLERY / F-STORYNo 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)

ObjetivoMétodo en este casoSalida
Entender actores de la naveModelado de stakeholders + personas§3–4
Definir job de «coger Sala 2 dos horas» y de ver ocupaciónJTBD + stories Must§5
Mapear fricción WhatsApp / taquilla / escenario → kioskJourney + service blueprint§6–7
Traducir a requisitos L2 kiosk + turnoMatriz 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

ProhibidoPermitido
«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 realQuotes de persona etiquetadas como constructo de diseño
Volumen medido «17 horas/día en Yeserías» como KPI de mercadoHoras de seed de producto, etiquetadas como demo
Horario oficial de una nave concreta de CarabanchelTurno 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

StakeholderInfluenciaInterésNecesidad principal
BANDA (Iván)Alta en la horaMuy altaCoger Sala 2 dos horas sin cuenta ni WhatsApp
CONSERJE (Lola)AltaMuy altaVer quién ocupa cada bloque de hoy
BATERÍA (Marta)MediaAltaMisma rejilla; la de batería a las cuatro
Nave / dueñaAlta formal, baja en producto día 1AltaQue se ocupen bloques; que no se confunda con concierto
Taquilla / ConciergoCompetencia / analogía falsaFuera de alcance; no clonar entradas
112 / emergenciasAlta en emergenciasFuera de alcance; no clonar el canal
Grupo de WhatsApp de la naveCanal paraleloNo es el backoffice
Público de conciertoNo 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)

CampoDetalle
Edad / contexto29 años; guitarra; banda Los Yesos; ensaya en nave de Carabanchel
DigitalMóvil con funda en el suelo; no quiere «otra cuenta de sala»; no compra entradas aquí
GoalsCoger Sala 2 dos horas; llevarse un código; no preguntar por WhatsApp
PainsEl 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

CampoDetalle
Edad / contexto47 años; conserje de la nave; turno de llaves y ocupación
DigitalFluida en desktop de mesa; el kiosk del pasillo no es su herramienta
GoalsVer el horario de hoy, saber quién tiene cada bloque, dar las llaves (fuera de app)
PainsWhatsApp 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 demolola@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)

CampoDetalle
Edad / contexto34 años; batería; coge Sala 1 porque hay kit
DigitalAlta; escribe rápido; no necesita onboarding
GoalsDejar la de batería apuntada; no montar un rider
PainsFormularios 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)

NombreRol en seedCódigo
Marta ChenP3 · Sala 1 16–18TM-2104
Cuarto AireCatálogoTM-2101, TM-2108
Tres CablesCatálogoTM-2102, TM-2107
Papel FumadoCatálogoTM-2103
Las CajasCatálogoTM-2105
Eco BajoCatálogoTM-2106
Los YesosP1 · 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énPor qué no es target v1
Promotor de ConciergoS3: no hay taquilla ni entradas
Público que quiere «entradas de esta noche»TEMPLE no vende entradas
Quién llama por un infartoTEMPLE no es 112
Operadora de PREGÓN que espera 3 columnasOtro job, otro día
Colorista de MATIZ que espera Hoy bentoOtro job, otro día
Dueña que quiere TPV y 12 salas el día 1H3 / S1: 3 salas, 5 bloques
Banda que quiere rider y backline extraS4

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

JobRol
Distinguir hora de conciertoBANDA / CONSERJE
Entender que no es taquillaBANDA / nave
Entender que la sala no es escenarioBANDA / nave
No crear cuentaBANDA
Ver ocupación de hoy como horarioCONSERJE
No ver nombres ajenos en el pasilloBANDA (D9)

Stories Must (v1)

IDStoryAC
US1Como músico, quiero ver las 3 salas sin cuentaGET /api/rooms · lead + 3 datos en el fold
US2Como músico, quiero ver los bloques de 2 h de hoyGET /api/rooms/:slug · 5 slots
US3Como músico, quiero confirmar con el nombre de la bandaUI-04 · POST bandName
US4Como músico, quiero un código al cogerPOST → TM-XXXX · /ok/:code
US5Como músico, quiero que el ticket no sea una entradaCopy hora ≠ concierto · no vende entradas
US6Como conserje, quiero entrar con email/passwordJWT + redirect /turno
US7Como conserje, quiero ver el horario de hoyGET /api/turno · 8/15 en seed
US8Como conserje, quiero leer el nombre de la banda en cada celdaHorario, no kanban
US9Como cualquiera sin token, no quiero ver el turno401 / redirect login
US10Como músico, no quiero ver el nombre de otras bandas en el kioskSlots free / taken
US11Como músico o conserje, quiero empty / error / loadingUI-08, UI-09, UI-10
US12Como músico en el pasillo, quiero targets ≥44pxKiosk 390 + UI-11
US13Como músico, quiero que un bloque cogido no se pueda volver a coger409 + unique

MoSCoW (v1 L2)

PrioridadÍtems
MustKiosk 3 salas, rejilla de horas, confirmar, ticket, login, turno horario, estados, empty/error/loading, kiosk mobile, unique slot
ShouldGhost Turno en kiosk; pie «no vende entradas»; logout en turno; 409 en UI
CouldGET /api/me; cancelar hora CONSERJE; grey de bloques pasados; ?day=
Won’tCuenta de banda, entradas, 112, kanban, chat, pago kiosk, calendario semanal, rider

6. Journey (BANDA · Sala 2 a las seis + CONSERJE)

FaseActorAcciónTouchpointEmoción [HIPÓTESIS]
1 Ver las salasIvánAbre /; lee 3 salas (lead + 3 datos)Kiosk H-KIOSKOficio, «esto no es taquilla»
2 Elegir salaIvánToca Sala 2 Combo/sala/comboConcentración (funda, pasillo)
3 Elegir horaIvánToca 18–20 (libre)RejillaControl (H1)
4 ConfirmarIvánEscribe Los YesosUI-04Oficio, no rider
5 Hora ≠ conciertoIvánVe el código; lee el disclaimer/ok/:codeLímite claro (H2)
6 Entrar a turnoLolaLogin JWT; aterriza en horario/login/turnoOficio, «quién ocupa»
7 LecturaLolaLee Marta Chen en Sala 1 16–18; ve Combo 18–20 Los Yesos tras el POST/turnoControl (H3)
8 Llaves (fuera)LolaDa las llaves en ventanilla; cobra fueraBackstageEl producto no finge el candado
9 No taquillaLolaNo hay aforo ni entradaAusencia de UIIntegridad

Momentos de verdad

  1. 3 salas + 3 datos en el primer viewport — si hay que «descubrir la marca», se rompe H-KIOSK / AP-21. [HIPÓTESIS]
  2. Sin cuenta — si aparece «regístrate», S2 / H3 fallan.
  3. Success dice que hora no es concierto — evita la mentira de la entrada.
  4. Cero CTA de entradas y cero 112 como envío — si aparece «Comprar entrada» como primary, el microcopy falla.
  5. Horario, no kanban — S-MIN / F-BOOK staff. [HIPÓTESIS]
  6. Bloque cogido no se recoge — 409 visible. [DECISIÓN]

7. Service blueprint (resumen)

CapaElementos
Frontstage BANDAKiosk, salas, rejilla, confirmar, ticket. Sin turno
Frontstage CONSERJELogin, horario de hoy
BackstageLlaves físicas, cobro en ventanilla, WhatsApp de la nave, Conciergo (fuera), 112 (fuera)
SistemasNest API :3021, Neon divine-haze-05909195, JWT, Angular
SoportesSeed 1 CONSERJE + 3 salas + 8 horas + fotos, Paper, docs
Fallos0 salas; 0 horas libres; 409 slot; 401 en turno; red caída → UI error

Fallos de servicio y respuesta de diseño

FalloEvidencia de UIRecuperación
0 salasUI-08 Empty kiosk«Aún no hay salas.»
0 horas libres en una salaUI-08 Empty slots«Hoy no queda hora en esta sala.» + volver
Slot cogido al POST409«Esa hora ya está cogida.» + rejilla refresca
API caídaUI-09 ErrorReintentar
Latencia kioskLoading (doc 16)Skeleton 3 salas
Form inválidoInline fieldNo navegar a /ok
Código inexistente en ticketTicket genéricoMuestra el código de la URL + copy; no inventa la hora
Sin token en /turnoRedirect/login
POST spam429 ShouldRate limit L+1

8. Matriz hallazgo → requisito → feature

HallazgoTipoRequisitoFeature v1
Coge hora en el pasillo, funda en el suelo[SUPUESTO] S2Kiosk 390/1440, targets ≥44, sin cuentaH-KIOSK · UI-01/02
Pregunta «¿está libre la 2?» por WhatsApp[HIPÓTESIS] H13 salas + rejilla de hoyGET rooms + slots
Hora se lee como concierto[HIPÓTESIS] H2Copy irrenunciableUI-05 Success
Sala se lee como escenario[DECISIÓN]Copy irrenunciableKiosk + ticket
El canal se lee como 112[DECISIÓN]Copy de límitePie kiosk
El tablero se lee como kanban[DECISIÓN]Horario, no columnasUI-07 Turno
Pago / rider el día 1[DECISIÓN] S4Cero pasarela, cero backline extraConfirmar solo nombre
Banda no necesita login[HIPÓTESIS] H3Público POST + JWT solo turnoGuards
L2 compacto, no PMS[DECISIÓN]3 salas, 5 bloques, hoyF-BOOK
Nombres ajenos en el pasillo[DECISIÓN] D9Kiosk: free/takenGET :slug sin bandName

9. Preguntas abiertas (no bloquean v1)

IDPreguntaCó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étodoMuestra orientativaPregunta
Test de usabilidad kiosk 390 / 14405–6 músicos 20–40¿Cogen un bloque en < 60 s sin cuenta?
Shadowing de turno1 conserje de nave¿El horario sustituye el WhatsApp?
Revisión de expectativa conciertoComentarios «¿entrada?»Validar H2
Recorrido con teclado + letra grande5 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

PrincipioAplicación
Kiosk firstLa home son las 3 salas. No hay landing de marca por delante
Público / turnoEl músico coge hora sin cuenta; Lola entra con JWT
Sala → hora → ticketProfundidad 2 desde el kiosk hasta el código
Turno = horarioFilas de bloques, columnas de salas; no kanban
Lenguaje de dominioSala, hora, ticket, turno — no «entrada», «lead», «expediente», «parte»
Hora no es conciertoEl ticket no tiene aforo ni puerta
Sala no es escenarioEl cuarto tiene moqueta, no palco
Chrome mínimoS-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

AudienciaNodos relevantes
BANDA / BATERÍAKiosk → Sala → Ok. No ven turno
CONSERJELogin → Turno · (puede leer el kiosk)
Taquilla / 112Ninguno 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)

ElementoDestinoNotas
Wordmark TEMPLE/No es hero; es sello del quiosco
Eslogan«La hora, no el concierto.»
Card sala/sala/:slug3 tiles enormes
Pie / link Turno/login o /turno si hay tokenSecundario, 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)

SlotDestinoVisibilidadNotas
Wordmark/turnoAuthNo lleva al kiosk
HoyAuthFecha de ocupación, no selector de mes
Salirlimpia token → /loginAuthCabecera, 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

SuperficieIzquierdaCentroDerecha
Kiosk /WordmarkTurno (ghost)
Sala /sala/:slug← SalasNombre de sala
OkWordmarkCoger otra
LoginWordmark
TurnoWordmarkHoyLola · 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)

ElementoDestinoNotas
Email / password / EntrarPOST login → /turnoJWT
Errorno navegaInline
Pieno «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

PantallaContenidos
Kiosk /Wordmark, eslogan, 3 salas (foto, lead, 3 datos), disclaimers, empty, loading, error
Sala /sala/:slugFoto, nombre, kind, m², rejilla 5 bloques, estado confirmar
ConfirmarSlot elegido, nombre de banda, «se paga en ventanilla», Coger hora
Success /ok/:codeCódigo, sala, bloque, «hora ≠ concierto», «no vende entradas», CTA coger otra
Login /loginWordmark, eslogan, email, password, submit, error, volver al kiosk
Turno /turnoCabecera S-MIN, matriz horario (sala × bloque × banda), empty, loading, error
Empty0 salas · 0 horas libres
ErrorRed · 409 slot cogido
LoadingSkeletons de 3 salas / rejilla / matriz
Kiosk mobile3 salas apiladas · rejilla 390

5. Taxonomía

Role

Status APILabel UISemántica
CONSERJEConserjeÚnico rol autenticado v1

[DECISIÓN] No hay BANDA / TAQUILLA / OPERADOR / COLORISTA.

BookingStatus

Status APILabel UISemántica
CONFIRMEDCogidaHora tomada; no es entrada ni concierto

v1 no tiene CANCELLED como Must. L+1: cancel CONSERJE. [DECISIÓN]

Slot

APILabel UI
10-1210–12
12-1412–14
16-1816–18
18-2018–20
20-2220–22

Orden de filas: 10–12 → 12–14 → 16–18 → 18–20 → 20–22.
No existe 14-16. [DECISIÓN] D13

Kind / Room

API slugKindLabel UI
bateriabateriaSala 1 Batería
combocomboSala 2 Combo
secasecaSala 3 Seca

SlotStatus (kiosk)

APILabel UISemántica
freeLibreSe puede coger
takenCogidaNo se puede coger; sin nombre de banda

Salas (líneas seed)

slugNombreLead3 datos
bateriaSala 1 BateríaKit dentroBatería · 12 m² · 2 de 5 libres
comboSala 2 ComboAmp + PA chicoCombo · 18 m² · 2 de 5 libres
secaSala 3 SecaSin bateríaSeca · 10 m² · 3 de 5 libres

[COMPROBADO] Tres salas del encargo. [DECISIÓN]

Horas (líneas seed)

codeslugslotbandName
TM-2101bateria10-12Cuarto Aire
TM-2102combo10-12Tres Cables
TM-2103seca12-14Papel Fumado
TM-2104bateria16-18Marta Chen
TM-2105combo16-18Las Cajas
TM-2106seca18-20Eco Bajo
TM-2107bateria20-22Tres Cables
TM-2108combo12-14Cuarto 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 mentalRepresentació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

RutaQuery / stateUso
/login?next=/turnoRedirect post-login sanitizado
/sala/:slugstate slot o ?slot=18-20 (Should)Abre confirmar
RestoSin ?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

UIAPI
Kiosk / salasGET /api/rooms público
RejillaGET /api/rooms/:slug público
Coger horaPOST /api/bookings público
LoginPOST /api/auth/login
TurnoGET /api/turno JWT
SaludGET /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

IdeaPor qué no en L2 v1
/entradas aforoRompe H2; eso es Conciergo
Área «mis horas» con cuentaCuenta de facto; contradice H3
Nombres de otras bandas en el kioskPrivacidad de pasillo; D9
Search como homeH-SEARCH de otros días
Chat de incidenciasH-CHAT de PREGÓN
Kanban Recibido / En cursoF-KAN de PREGÓN
Hoy bento de sillasH-BENTO de MATIZ
Wizard de 3 pasosZAGUÁN
Lookbook editorialH-GALLERY de MARGEN
/concierto / /112Rompe microcopy
Bottom tabs Kiosk · Turno · CuentaMezclaría oficios; el músico no tiene turno
Top-nav Conciertos / Agenda / TiendaMarketing de sala; contradice el brief
Calendario semanalD13: 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
PasoAcciónSistema
1Aterriza en el kioskRouter público
2Lee 3 salas (lead + 3 datos)UI-01 / UI-02
3No 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
PasoAcciónSistema
1Lee Sala 1 Batería, Sala 2 Combo, Sala 3 Secarooms
2Lee 3 datos por sala (kind, m², libres de 5)UI
3Toca una salaRouter /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.

CasoComportamiento
0 salasUI-08: «Aún no hay salas.»
Red / 5xxUI-09 + Reintentar (repite GET)
Primera cargaSkeleton 3 tiles (doc 16)

F2 — Ver horas (Guest) · F-BOOK

/sala/:slug → GET /api/rooms/:slug
  → 5 bloques free|taken  |  empty  |  error  |  skeleton
PasoAcciónSistema
1Lee nombre de sala y fotoRoom
2Lee 10–12 … 20–22slots
3Toca un bloque freeAbre confirmar (UI-04)
4Toca un bloque takenNo 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]

CasoComportamiento
0 libresUI-08: «Hoy no queda hora en esta sala.» + ← Salas
Red / 5xxUI-09 + Reintentar
Primera cargaSkeleton rejilla (doc 16)
Slug inexistente404 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
CampoValidación cliente (mín.)API
bandNamerequired, min 2, max 80@MinLength(2)
roomSlugde la rutabateria | combo | seca
slotseleccionado, enum10-12 | 12-14 | 16-18 | 18-20 | 20-22
dayno en POST; siempre hoyservidor fuerza today Europe/Madrid
statusno en POST; siempre CONFIRMEDservidor fuerza CONFIRMED
codeno en POSTservidor asigna TM-XXXX

Éxito: registro status=CONFIRMED + pantalla ticket.
No hay «Entrada» ni «Escenario» ni pago en v1.

JSON camelCase: bandName, roomSlug. [DECISIÓN]

GestosResultado
Slot libreSelecciona; abre confirmar
Nombretext
Coger horaPOST; pending en botón
InválidoInline; no POST
Doble submitBotón disabled mientras pending
Cancelar confirmarVuelve a rejilla; no POST

Errores

CasoComportamiento
Validación DTO400 + mensaje de campo
Slot ya cogido409 SLOT_TAKEN · rejilla refresca · no navegar a /ok
Red caídaError de red en form; no navegar a /ok/…
429Should: «Espera un momento para coger otra.»
Slot / slug fuera de enum400

[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 → /
PasoAcciónSistema
1Lee código y copyUI-05
2No abre el turnoGuard
3Puede coger otraRouter

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
CampoValidación clienteAPI
emailrequired, email@IsEmail()
passwordrequired, min 6@MinLength(6)

Éxito: token guardado; user role=CONSERJE, nombre Lola Rivas.
Credencial demo: lola@temple.nave / password123.

CasoComportamiento
Credenciales inválidas401 + mensaje
Red caídaError de red en UI
Token caducado en turno401 en GET → re-login
next externo / //Ignorado; va a /turno
Banda en loginNo 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
PasoAcciónSistema
1Lee filas 10–12 … 20–22slots
2Lee columnas Sala 1 / 2 / 3rooms
3Lee banda o «Libre» en cada celdaBooking | 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]

CasoComportamiento
0 horas en el díaUI-08: «Hoy no hay horas apuntadas.» (salas siguen existiendo)
Red / 5xxUI-09 + Reintentar
Primera cargaSkeleton matriz (doc 16)
Sin tokenRedirect /login
401 mid-sessionRedirect /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
CasoComportamiento
SalirBorra temple_token + temple_user
Tras salir, /turnoRedirect 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ódigoCuándoUI
400DTO inválidoMensaje campo / genérico
401Sin/mal token en turnoRe-login
404slug no existeMensaje + volver al kiosk
409Slot cogido«Esa hora ya está cogida.» + refresh rejilla
429Rate limit POSTEspera
5xx / networkAPI caídaError + 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:

EntidadTabla SQLPropósito
UserusersIdentidad de oficio (rol CONSERJE)
SessionsessionsSesión JWT / token persistido (Should)
RoomroomsSala de ensayo (batería / combo / seca)
BookingbookingsHora 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

ValorDescripción
CONSERJEConserje del turno; único rol autenticado v1

BookingStatus

ValorDescripción
CONFIRMEDHora 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.
bookings no apunta a users: la hora es anónima de cuenta.

4. Tablas

users

CampoTipoConstraints
idTEXTPK
emailTEXTUNIQUE NOT NULL
password_hashTEXTNOT NULL (bcrypt)
nameTEXTNOT NULL
roleTEXTNOT NULL DEFAULT 'CONSERJE'
nave_nameTEXTNOT NULL DEFAULT 'TEMPLE · Carabanchel'
created_atTIMESTAMPTZDEFAULT now()
updated_atTIMESTAMPTZDEFAULT now()

sessions

CampoTipoConstraints
idTEXTPK
user_idTEXTNOT NULL FK → users(id) ON DELETE CASCADE
token_hashTEXTNOT NULL
expires_atTIMESTAMPTZNOT NULL
created_atTIMESTAMPTZDEFAULT 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

CampoTipoConstraints
idTEXTPK
slugTEXTUNIQUE NOT NULL · bateria | combo | seca
nameTEXTNOT NULL
kindTEXTNOT NULL CHECK IN (bateria,combo,seca)
size_m2INTEGERNOT NULL
leadTEXTNOT NULL
coverTEXTNOT NULL · filename (bateria.jpg)
sort_orderINTEGERNOT NULL DEFAULT 1
created_at / updated_atTIMESTAMPTZ

[DECISIÓN] GET público lista sort_order asc. L+1: salas inactivas.

bookings

CampoTipoConstraints
idTEXTPK
codeTEXTUNIQUE NOT NULL · ^TM-\d{4}$
room_idTEXTNOT NULL FK → rooms(id)
dayDATENOT NULL
slotTEXTNOT NULL CHECK IN (10-12,12-14,16-18,18-20,20-22)
band_nameTEXTNOT NULL
statusTEXTNOT NULL DEFAULT 'CONFIRMED'
created_at / updated_atTIMESTAMPTZ

UNIQUE (room_id, day, slot).
[DECISIÓN] SQL snake_case (band_name, room_id); JSON camelCase (bandName, roomId).

5. Reglas de integridad y negocio

ReglaImplementación
Lectura de salasPública
Lectura de rejillaPública · slots free / taken sin bandName
Alta de horaPública · status forzado CONFIRMED · code asignado · day = hoy Europe/Madrid
Lectura de turnoJWT CONSERJE → 401 sin token · bandName
Login / healthPúblicos
PasswordNunca en claro; solo password_hash
Orden salassort_order asc
Orden bloques10-12, 12-14, 16-18, 18-20, 20-22
POST Bookingno emite entrada; no cobra; no llama al 112
Público nunca lista bookingsno hay GET público de horas ajenas
Cover allowlistfilenames seed
Códigosecuencial TM- + 4 dígitos; seed hasta 2108 → siguiente 2109
Choque de horaUNIQUE → 409 SLOT_TAKEN
Solo hoyPOST 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

CampoTipoReq
roomSlugbateria | combo | seca
slot10-12 | 12-14 | 16-18 | 18-20 | 20-22
bandNamestring 2–80

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

NombreEmailPasswordNave
Lola Rivaslola@temple.navepassword123TEMPLE · Carabanchel

[COMPROBADO] Credencial del encargo. Nombre de pila es constructo de diseño.

Rooms (3)

idslugnamekindsize_m2leadcoversort
rm_1bateriaSala 1 Bateríabateria12Kit dentrobateria.jpg1
rm_2comboSala 2 Combocombo18Amp + PA chicocombo.jpg2
rm_3secaSala 3 Secaseca10Sin bateríaseca.jpg3

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.

codeslugslotbandName
TM-2101bateria10-12Cuarto Aire
TM-2102combo10-12Tres Cables
TM-2103seca12-14Papel Fumado
TM-2104bateria16-18Marta Chen
TM-2105combo16-18Las Cajas
TM-2106seca18-20Eco Bajo
TM-2107bateria20-22Tres Cables
TM-2108combo12-14Cuarto 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-20TM-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)

CambioNivel
Ticket público mínimo { code, roomName, slot }L+1
Cancel CONSERJEL+1
Grey de bloques pasadosL+1
Segundo CONSERJEL+1 / L3
Calendario ?day=L+1 / L3
Soft delete + audit logL3
Pago / taquilla / entradasFuera (H2 / S4)
Cuenta de bandaFuera (H3)
112 / kanban / chatFuera (microcopy / terna)

06-tech-stack.md

06 — Stack tecnológico — TEMPLE

1. Visión

CapaTecnologíaNotas
FrontendAngular standalone + signalsPuerto 4200 · web kiosk-first
EstilosTailwind CSSTokens vehicle dashboard (ink, panel, cream, amber, mute, jewel)
BackendNestJS TypeScriptPuerto 3021, prefijo /api
PersistenciaPostgreSQL (ensureSchema o Prisma)Tablas users, rooms, bookings (+ sessions Should)
DBNeon PostgreSQLproject divine-haze-05909195
AuthJWTRol CONSERJE (turno); kiosk y POST bookings públicos
DiseñoPaper01M0HJ2Z7NJSYC0FDMWYSSQBG3
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:

ScriptAcción
apiArranca Nest en :3021
start / webArranca Angular en :4200

3. API pública vs JWT

MétodoRutaAuth
GET/api/healthPúblico · { ok: true, service: "temple-api" }
GET/api/roomsPúblico
GET/api/rooms/:slugPúblico
POST/api/bookingsPúblico
POST/api/auth/loginPúblico
GET/api/turnoJWT 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ónRazón
Angular + NestAlineación con la serie daily y el handoff del estudio
Neon serverlessVolumen bajo (S1: 12–20 h/día; demo 3 salas × 5 bloques); no cola Redis
JWT CONSERJED-P1-05: turno interno cerrado; el kiosk sí es público
Auth en servidor para turnoSource of truth = guard; el cliente no «esconde» nombres de banda
Puerto 3021Evitar 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-XXXXTicket humano, no UUID en el pasillo
Unique (room, day, slot)Dos bandas no caben a la misma hora

5. Variables

.env local (nunca git):

VariableServicioDescripción
DATABASE_URLAPINeon divine-haze-05909195
JWT_SECRETAPIFirma tokens
PORTAPIopcional, 3021
JWT_EXPIRESAPIopcional (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 (jose o @nestjs/jwt)
  • bcrypt (o bcryptjs)
  • 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

NoPor qué
npm workspacesAP-06
Firebase AuthStack fijo JWT + Neon
Next.js / ReactD-P0-03
Pasarela / Stripe MustS4: ventanilla
Redis / colas15 slots no lo necesitan
Ticketing / aforoHora ≠ concierto
112 / CADTEMPLE no es 112
Chat / kanban APITerna 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

EjeNo
SuperficieInk #12110F, panel #1E1C18, cream de dialFog PREGÓN, yeso MATIZ, hormigón ZAGUÁN, papel MARGEN, musgo CESTA
TipoFraunces display + Atkinson Hyperlegible UIIbarra+Jost, Libre Baskerville+Nunito, Instrument+Sora, Cormorant+Public Sans, Spectral+Manrope
FotoSala de ensayo: kit, combo, seca; moqueta, no palcoEscenario, público, neón de concierto, «banda en portada»
Grid3 salas enormes; rejilla de 2 h; horarioHero 2-col + 3 cards de features (AP-12)
AcentoAmber #E8A317 en coger, bloque libre, LEDMark lima PREGÓN, amatista chapel, óxido inmobiliario
ChromeCasi sin nav (S-MIN)Rail de kanban, bottom tabs, masthead, wizard 1—2—3

3. Paleta

TokenHexRol
Ink / G-INK#12110FGround de página. Negro de instrumento, no fotocopia.
Panel#1E1C18Superficie de card / dial / celda. Nunca el fondo de página.
Cream#F4EBD0Texto, wordmark, cuerpo. Crema de dial.
Amber#E8A317LED / gaffer: CTA Coger, bloque libre, foco
Mute#8C8474Meta, labels, hora secundaria, idle
Jewel#C23B22Acento 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

UsoFamiliaTamaños de referencia
WordmarkFraunces 70024–28 desktop · 22 mobile
Titular de kiosk / turnoFraunces 70032–40
Código TM-XXXXFraunces 70028–36
Nombre de salaFraunces 70022–28
Cuerpo / disclaimersAtkinson Hyperlegible 40016–17 / 26–28 lh
UI, chips, form, rejillaAtkinson Hyperlegible 400/500/70014 / 16
Meta (hora, m², kind)Atkinson Hyperlegible 50012–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:

AssetLectura visualUso
hero.jpgNave / flight case / tablero ámbar, no escenarioCover UX · atmósfera, no hero de marketing en /
salas/bateria.jpgKit, moqueta, cuarto cerradoSala 1
salas/combo.jpgAmp, PA chico, ensayo de grupoSala 2
salas/seca.jpgCuarto seco, sin bateríaSala 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 ││
│  └─────────┴─────────┴─────────┘│
└─────────────────────────────────┘
  1. Wordmark + eslogan (una línea, no portada).
  2. Lead en el fold: 3 salas (foto, nombre Fraunces, 3 datos Atkinson).
  3. 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

SuperficieSpec
Hover tile salaRule cream 1px; no elevación 8px ni scale 1.04
Coger horaFade 160ms al ticket; off si reduced-motion
Bloque libreAmber LED estático; no parpadeo
SkeletonPulso 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 / nocturnalPrimer 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» stockMentira social del concierto
Azul institucional de taquillaEntradas; contradice R-HY dashboard
Iconos outline de guitarra 2014Chrome 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

  1. Ground de página = #12110F. Cards = #1E1C18. Nunca al revés.
  2. Amber en el CTA Coger y en el bloque libre, no un header naranja lleno.
  3. 3 salas visibles en el primer viewport (lead + 3 datos).
  4. Ninguna fuente de la lista vetada. Fraunces + Atkinson Hyperlegible.
  5. Home reconocible como quiosco de salas, no como hero 2-col de concierto.
  6. Success no celebra un «ya estáis en el escenario» ni una entrada.
  7. Jewel solo en error / sello, no en el chrome.
  8. 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):

KeyValor
colors.ink#12110F
colors.panel#1E1C18
colors.cream#F4EBD0
colors.amber#E8A317
colors.mute#8C8474
colors.jewel#C23B22
fontFamily.displayFraunces
fontFamily.sansAtkinson Hyperlegible

[COMPROBADO] Hex y tipo = brief.

2. Escala tipográfica

TokenFamiliaSize / lhUso
display-lFraunces 70040 / 44Titular turno desktop · código ticket
display-mFraunces 70028 / 32Nombre sala · wordmark
display-sFraunces 70022 / 28Nombre sala 390
codeFraunces 70024 / 28TM-XXXX
bodyAtkinson 40016 / 26Disclaimers, confirmar
uiAtkinson 40016 / 24Form, lista, rejilla
metaAtkinson 50013 / 18Hora, m², kind
slotAtkinson 70016 / 2010–12 · Libre / Cogida

3. Componentes

RoomTile (H-KIOSK)

SpecValor
Desktop3 columnas iguales, min-height ~520–640, foto 4:3 cover
3901 col, misma foto + 3 datos, target ≥44
Contenidonombre Fraunces · lead · kind · m² · «N de 5 libres»
Superficiepanel sobre ink
Hoverrule 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)

SpecValor
DesktopPanel derecho o modal no-modal bajo la rejilla, max 480
390Hoja inferior, safe-area
CamposbandName · label visible
CTACoger hora · fondo amber · texto ink · h-44
Disclaimers«Hora cogida ≠ concierto.» · «Se paga en ventanilla.»
CerrarVolver 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)

SpecValor
DesktopTabla 5 filas × 3 columnas + cabecera de salas
Celda takenpanel + bandName cream
Celda free«Libre» mute
CabeceraFraunces 22 salas · Atkinson 13 horas
3903 bloques apilados (una sala cada uno), mismas filas

No es un kanban. No hay chips Recibido / En curso. [DECISIÓN]

Botones

VarianteUsoSpec
PrimaryCoger hora, EntrarFondo amber, texto ink, h-44, radius 4
SecondaryCoger otra, volverRule cream, texto cream, fondo ink
GhostTurno (en kiosk), Salir, ReintentarTexto mute
DangerError 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

EstadoReceta
Empty kioskTitular Fraunces 28 + 1 línea Atkinson
Empty slotsTitular + 1 línea · «Hoy no queda hora en esta sala.» + ← Salas
ErrorBanner filete jewel + texto + Reintentar
Loading kiosk3 tiles panel
Loading slots5 celdas
Loading turnomatriz 5×3
404 sala«Esa sala no está.» + link al kiosk
409«Esa hora ya está cogida.» + rejilla

4. Grid y breakpoints

ViewportComportamiento
≥1200Kiosk 3 col; slots max 720; turno matriz completa
960–1199Kiosk 3 col compactas; turno matriz
600–959Kiosk 1 col; turno apilado por sala
~390Kiosk 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.

SitioRecurso
KindTexto (Batería / Combo / Seca). Icono trazo 1.5 de 20px opcional
LibreFilete amber, no check clip-art
EmptyNada o una rule amber de 32px
StatusTexto 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

SuperficieTratamiento
PáginaInk plano
Tile / slot / celdaPanel plano + rule 1px mute 30%
Libre+ filete amber
ModalNo hay modal Must (confirmar es hoja/panel)

Cero sombras shadow-lg. El flight case no flota.

7. Mapa componente → ruta

ComponenteRutas
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

  1. Tokens Tailwind = hex del brief, sin fog PREGÓN #F1F3F6 como ground.
  2. Cards en panel; página en ink.
  3. Primary CTA amber + texto ink (nunca mute sobre ink como único CTA).
  4. Fraunces no aparece en labels de form ni en meta 12px.
  5. Recorte de sala aspect-[4/3], no 16:9 de escenario.
  6. Targets de tiles, slots y CTA ≥44px (slots kiosk ≥56 preferible).
  7. 3 datos de sala visibles sin hover.
  8. 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

UsarNo usar
Hora / bloque / cogerEntrada, ticket de concierto, aforo, puerta
SalaEscenario, palco, recinto, venue
Ticket (de hora) / códigoEntrada, pase, backstage
Cogida / libreReservado Booksy, «confirmada la cita», «en cartel»
Turno / ocupación / horarioKanban, Recibido, En curso, mesa de partes
Banda / nombre de bandaRider, backline extra, rider técnico
VentanillaPagar ahora, Stripe, TPV (en UI)
TEMPLE no vende entradasComprar, 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ónDóndeCopy
Hora cogida ≠ conciertoConfirmar sobre CTA · ticket · pie de kiosk«Hora cogida no es concierto. TEMPLE no pone un escenario.»
Sala ≠ escenarioTile de sala · ticket · turno pie«Esto es una sala, no un escenario. Es un cuarto con moqueta.»
TEMPLE no vende entradasTicket · confirmar · login pie«TEMPLE no vende entradas. Se paga la hora en ventanilla.»
Ensayar no es actuarTicket · 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

SuperficieCopy
EsloganLa hora, no el concierto.
Línea de naveTEMPLE · Carabanchel
Kiosk titularTEMPLE
Tile dato 1Batería / Combo / Seca
Tile dato 212 m² / 18 m² / 10 m²
Tile dato 32 de 5 libres
Sala volver← Salas
Slot libreLibre
Slot takenCogida
Confirmar titularCoger 18–20
Confirmar nombreNombre de la banda
Confirmar submitCoger hora
Confirmar disclaimer 1Hora cogida no es concierto.
Confirmar disclaimer 2Se paga en ventanilla. TEMPLE no vende entradas.
Login titularEntrar al turno
Login ayudaSolo conserje. La banda coge hora en el kiosk, sin cuenta.
Login submitEntrar
Login errorEmail o contraseña no valen.
Login volverVolver al kiosk
Empty kioskAún no hay salas.
Empty slotsHoy no queda hora en esta sala.
Empty turnoHoy no hay horas apuntadas.
Success titularHora cogida.
Success códigoTM-2109
Success cuerpoHora cogida no es concierto. TEMPLE no vende entradas.
Success salaSala ≠ escenario. Ensayar no es actuar.
Success CTACoger otra
ErrorNo hemos podido cargar el kiosk.
Error retryReintentar
Error 409Esa hora ya está cogida.
Loading kioskAbriendo las salas…
Loading slotsAbriendo las horas…
Loading turnoAbriendo el turno…
404 salaEsa sala no está.
Turno titularTurno
Celda libreLibre
SalirSalir
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.

PiezaTono
Sala 1 BateríaKit dentro. Moqueta. Sin palco.
Sala 2 ComboAmp y PA chico. Grupo.
Sala 3 SecaSin batería. Escritura / acústico.
TM-2104 Marta ChenNombre 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

NombreUso
Iván MoraBANDA; sin cuenta; guitarra, Los Yesos
Lola RivasCONSERJE; lola@temple.nave
Marta ChenBATERÍA; sin cuenta; seed Sala 1 16–18
Los YesosBanda de Iván; POST demo
Cuarto Aire, Tres Cables, Papel Fumado, Las Cajas, Eco BajoBandas catálogo
TEMPLE · CarabanchelNave 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

StatusFrase UIFrase que Lola podría decir (fuera de app)
LibreLibre«Está libre. Cogedla en el quiosco.»
Cogida / CONFIRMEDCogida«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–12 en UI (en-dash); 10-12 en API.
  • Fecha: 21 ago en cabecera de turno; viernes 21 de agosto si hay línea larga.
  • No mezclar tm-2109 en 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

NoMotivo
«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 / CerradoNo es kanban
Ranking de las bandas de la naveLikes, otro producto
Lorem / «lorem ipsum sala»Prohibido en el case
Declaraciones inventadas de una nave realVerdad 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

TemaDecisión
Tipo UIAtkinson Hyperlegible ≥16px body
DisplayFraunces no se usa por debajo de 20px
ContrasteCream #F4EBD0 sobre #12110F / #1E1C18
CTA amberTexto ink sobre #E8A317
Jewel errorTexto jewel sobre ink o jewel + cream, nunca jewel sobre amber
FocoOutline 2px amber, offset 2px, visible (no outline-none global)
Tiles<a> con nombre + 3 datos en texto
RejillaLabels visibles; aria-pressed / aria-disabled en slots
Imágenesalt = sala + kind
FormLabels visibles, no placeholder-only
ErroresTexto, no solo color
Mobile / kioskTargets ≥44px (tiles, slots, Coger) · S2 funda en el suelo
MovimientoFade 160ms; prefers-reduced-motion: reduce → 0
Live regionsaria-live="polite" en empty/error de kiosk, slots y turno

2. Contraste (comprobación de diseño)

ParUsoNota
#F4EBD0 / #12110FBody sobre inkPasa AA y AAA cuerpo
#F4EBD0 / #1E1C18Body sobre panelPasa AA
#12110F / #E8A317CTA CogerPasa AA para texto ≥14px bold; no usar blanco sobre amber
#8C8474 / #12110FMeta muteVerificar ≥13px; no usar en 11px
#8C8474 como texto 12px sobre panelProhibido para body
Slot idle muteSolo si no es el único indicador+ label textual Libre / Cogida
#C23B22 / #12110FError 409Verificar ≥16px; si falla, cream + rule jewel
Blanco / amber como textoProhibido (ámbar + blanco falla en UI pequeña)

3. Teclado

FlujoOrden
KioskWordmark → tile 1 → 2 → 3 → link Turno
SalaAtrás → slots en orden → (confirmar: nombre → Coger)
OkCódigo (lectura) → Coger otra
LoginEmail → password → submit → volver al kiosk
TurnoSalir → 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

PiezaMarkup
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">
Slotsrole="group" + aria-label="Bloques" · botones
Slot takenaria-disabled="true"
Slot selectedaria-pressed="true"
Confirmar<form aria-label="Coger hora">
Turno<table> o grid con role="table" · encabezados de sala y hora
Aviso no-entradastexto normal; no alert de envío
Skeletonsaria-busy="true" en el contenedor; aria-hidden en placeholders

5. Lector de pantalla — copy

SituaciónAnuncio
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.»
ErrorAnuncio 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 hacerLo que no afirma
Targets 44px en el pasilloQue el pasillo de Yeserías sea accesible de hecho
Kiosk usable con teclado, zoom 200% y letra 16pxQue 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 libreQue Los Yesos sea identificable de forma legal
Foto de sala con altQue 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

RiesgoMitigación
Hoja confirmar tapa la rejilla en 390padding-bottom / scroll al form
Fraunces en meta 12pxProhibido; meta = Atkinson 13
Amber como único estado de libre+ label Libre
Foto sin altChecklist seed: 3 alts + hero
409 leído solo por color jewelLabel siempre
Iván con funda (S2)Targets ≥44; no gestos swipe; no hover-only; sin cuenta
CTA amber + texto blancoTexto ink
Leftover Ibarra / Jost / fogTokens TEMPLE
Matriz turno ilegible en 390Apilar por sala, no 3 col de 120px

8. QA a11y (mínimo)

#PruebaPasa si
1Teclado kiosk → sala → slot → okSin trampa; foco visible
2Teclado login → turnoAcciones alcanzables
3Zoom 200% móvil 390Slots usables; confirmar no solapa inputs
4Lighthouse a11y ≥ 90 en /Sin contrast fails de tokens
5VoiceOver/NVDA: tile y slot anunciadosNombre, hora, libre/cogida comprensibles
6prefers-reduced-motionSin stagger ni slide
7Contraste CTA amber + error jewelTexto ink sobre amber; 409 con texto

9. Criterios de aceptación

  1. Ningún control de tile, slot o CTA mide menos de 44×44 CSS px.
  2. El disclaimer no depende del color amber o jewel para ser entendido.
  3. Las 3 fotos de sala + hero tienen alt no vacío y no genérico.
  4. El foco no se pierde al reintentar un error de red o un 409.
  5. En 390 las 3 salas son alcanzables sin un carousel de marketing.
  6. Un turno no se anuncia en / sin token (no hay HTML público de nombres ajenos).
  7. 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

DatoDóndeBase / nota
Email y hash de la conserjeusersContrato interno del turno
Nombre de banda en la horabookings.band_nameTexto libre; no es una cuenta
Sala, día, bloquebookingsHora; catálogo seed · PII de atrezzo
Foto de salarooms.cover filenameSeed; no UGC v1
SalasroomsCatálogo; no PII
Sesión JWTAuthorization + 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 v1Por qué
Email / teléfono / DNI de la bandaH3 · no taquilla · no seguimiento
Geolocalización del dispositivoKiosk de pasillo
Rider / backline extraS4
Pago / tarjetaS4 · ventanilla
Foto subida por la bandaNo hay UGC Must
IP como identidadNo se usa como usuario
Nombres de otras bandas en el kioskD9

bandName es dato de hora demo, no un requisito de identidad legal. L+1 podría hacerlo opcional. [DECISIÓN]

3. Seguridad L2

ControlSpec
Auth turnoJWT Bearer · role === CONSERJE
Passwordbcrypt cost 12; nunca en response
Lectura turnoGET /api/turno → 401 sin token
Kiosk / POST hora / rooms / health / loginPúblicos
Rate limit/auth/login + POST /api/bookings (anti stuffing / spam; Should si no llega al slice)
CORSOrigen http://localhost:4200 en local
SecretosSolo .env (no git)
Cover allowlistFilenames seed; no URL arbitraria
next post-loginPaths relativos allowlist (/turno)
Guard webAngular en /turno
Ticket público/ok/:code no hidrata GET turno
Unique slot409; no overbooking
Kiosk slotsfree / 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

RiesgoMitigación v1
Enumeración de códigos TM-XXXXGET turno 401 sin token; ticket no lista otras horas
JWT en localStorageAceptable en demo; horas son atrezzo, no PII real de nave
Nombre de Marta en seedEl 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 bookingsUnique + rate limit Should; bandName max 80
Lola pide un kanbanD14: no hay fila de status de columnas
Iván pega un teléfono en bandNameCopy: «nombre de la banda»; no se pide; no se scrape
Open redirect nextAllowlist /turno
Double-bookUNIQUE + 409
Carrera de dos POSTs al mismo slotConstraint de BD gana; el segundo 409

5. Roles y autorización (recordatorio)

RecursoAnónimoCONSERJE
GET rooms / :slug / health / POST bookings / POST login
GET turno (nombres de banda)401
Entradas / 112 / kanbanNo existeNo existe

Iván, Marta y la dueña no tienen fila en users.

6. Criterios de aceptación

  1. Response de login no incluye password ni password_hash.
  2. GET /api/turno sin Bearer es 401, no 200 con nombres.
  3. POST /api/bookings sin Bearer es 201 (público) o 409.
  4. GET /api/rooms y GET /api/rooms/combo sin Bearer son 200.
  5. GET /api/rooms/:slug no incluye bandName en slots.
  6. No hay formulario público que pida DNI, email o teléfono.
  7. /turno sin token redirige a /login (no renderiza nombres en HTML anónimo).
  8. /ok/:code no llama a GET JWT.
  9. .env no se commitea.
  10. 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

EventoCuándoProps mín.
kiosk_viewRender de /rooms (0–n), freeTotal
room_openRender de /sala/:slugslug, free
slot_selectTap slot libreslug, slot
booking_createPOST 201code, slug, slot
booking_conflictPOST 409slug, slot
ok_viewRender de /ok/:codecode
conserje_loginJWT ok
turno_viewRender de /turnotaken, free
kiosk_empty0 salas
slots_empty0 libresslug
error_bannerUI-09surface

2. Qué no se mide

No eventoMotivo
signup_click / lead_submitNo existe CTA de cuenta de banda
ticket_purchased / entrada_soldTEMPLE no vende entradas
emergency_callTEMPLE no es 112
kanban_moveNo hay columnas
concert_checkinEnsayar no es actuar
like / favoriteFuera
Identidad de Iván como usuariaH3 · no es usuaria
bandName enviado a un terceroPII 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ñalCómo se observa
Turno cerradoGET /turno 401 sin token (QA, no analytics)
Kiosk abiertoPOST bookings 201 sin token
Expectativa de entradaComentarios cualitativos; cero evento ticket_purchased
Expectativa de 112Cero evento de llamada como conversión
Choque de horabooking_conflict 409
Salud4xx/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)

  1. Los eventos de §1 tienen nombre estable.
  2. No se dispara ningún evento de lead / entrada / 112-como-conversión / kanban / concierto.
  3. Un bloqueador de cookies no rompe el kiosk (analítica no es Must de runtime).
  4. slug y slot se miden; bandName no.

13-qa-test-plan.md

13 — Plan de pruebas — TEMPLE

1. Smoke obligatorio (D-P1-06)

#AcciónEsperado
1GET /api/health200 · { ok: true, service: "temple-api" }
2GET /api/rooms200 · 3 slugs bateria, combo, seca
3POST /api/auth/login lola@temple.nave / password123200 · accessToken · user.role=CONSERJE
4GET /api/turno con Bearer200 · 8 taken / 7 free · códigos TM-2101…2108
5ng build o serve webWeb arranca o build OK

[COMPROBADO] Smoke = health (temple-api) + rooms públicos + login JWT + turno JWT.

2. Casos funcionales

IDCasoEsperado
S1Códigos seedGET turno incluye TM-2101…TM-2108
S2Turno sin JWT401 (no 200 con nombres)
S3Rooms sin JWT200
S4Room slug sin JWT200 · slots sin bandName
S5POST bookings sin JWT201 · status=CONFIRMED · code TM-XXXX
S6POST Combo 18-20 Los Yesos201 · roomSlug=combo · slot=18-20
S7POST mismo slot otra vez409 SLOT_TAKEN
S8Slug inexistente404
S9Kiosk UI/ muestra 3 salas (lead + 3 datos); cero cuenta / entradas
S10Home es kiosk/ es H-KIOSK; no hero 2-col; no chat PREGÓN
S11Rutas turno/turno sin token → /login
S12Login malo401 · mensaje en form
S13Empty kiosk0 salas → UI-08
S14Empty slotssala sin libres → UI-08
S15API caídaUI-09 + Reintentar conserva la vista
S16LoadingSkeleton 3 tiles / rejilla / matriz
S17Mobile 3903 salas apiladas; slots ≥44px; confirmar usable
S18Fotos seedcovers bateria.jpg combo.jpg seca.jpg resuelven
S19Password no viaja de vueltalogin response sin hash
S20Body POSTacepta roomSlug, slot enum, bandName
S21Slot inválidoPOST slot 14-16 → 400
S22Success/ok/:code copy «Hora cogida no es concierto» · «no vende entradas»
S23Healthservice: "temple-api"
S24Conteos seed8 taken · 7 free
S25/ok/:code sin JWT funciona200 de página; no pide login
S26Microcopy ×4hora≠concierto · sala≠escenario · no entradas · ensayar≠actuar
S27Puerto APIproceso en 3021
S28Turno es horariono hay columnas Recibido / En curso
S29Kiosk no filtra nombresGET :slug sin bandName
S30Marta en turnoSala 1 16–18 = Marta Chen

3. Datos de prueba

UsoValor
CONSERJElola@temple.nave / password123
Hora feliz seedTM-2104 · Marta Chen · bateria · 16-18
POST feliz{ "roomSlug":"combo","slot":"18-20","bandName":"Los Yesos" }
POST choquemismo body tras el feliz → 409
Empty kioskborrar rooms (solo entorno de test)
Empty slotsPOST los 7 libres (test)

4. Regresión de diversidad / craft

CheckFalla si
Home es kioskHay hero 2-col + 3 cards de marca (AP-12) o chat PREGÓN o bento MATIZ
Shell es S-MINHay rail de kanban, bottom tabs o chrome 1—2—3 como nav primaria
Copy honestoTicket dice «entrada» o «escenario» como hecho, o hay «comprar» o CTA 112 de envío
PaletaSe cuelan fog+lima PREGÓN / amatista MATIZ / óxido ZAGUÁN
TipoIbarra Real Nova / Jost / Libre Baskerville / Nunito / Instrument / Sora
RutasAparecen /mesa, /chat, /entradas, /concierto, /112, /hoy
GroundPágina en fog #F1F3F6 o blanco total en vez de ink #12110F
Healthservice distinto de temple-api
TurnoKanban 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 .env en 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 AngularArtboard
Tokens ink/panel/cream/amber + Fraunces / AtkinsonUI-00
Kiosk home 1440 · 3 salas enormes · lead + 3 datosUI-01
Kiosk mobile 390UI-02
Rejilla bloques 2 h de hoyUI-03
Confirmar nombre de bandaUI-04
Success ticket «hora ≠ concierto»UI-05
Login CONSERJEUI-06
Turno horario (no kanban)UI-07
EmptyUI-08
ErrorUI-09
Loading skeletonsUI-10
Slots mobile 390UI-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

TemaContrato
Health{ ok: true, service: "temple-api" }
SalasGET /api/rooms público
RejillaGET /api/rooms/:slug público · slots free / taken sin bandName
Alta horaPOST /api/bookings público · body roomSlug, slot, bandName
Login{ accessToken, user } camelCase (no access_token)
TurnoGET /api/turno JWT → matriz con bandName
Status enumCONFIRMED
Slot enum10-12 | 12-14 | 16-18 | 18-20 | 20-22
Kind / slugbateria | combo | seca
RoleCONSERJE
CodeTM-XXXX
Choque409 SLOT_TAKEN
Puerto3021

Campos JSON en camelCase hacia el web aunque SQL sea snake_case. [DECISIÓN]

4. Mapa de rutas web

PathGuard clientePágina
/noKioskPage
/sala/:slugnoSlotsPage (incluye confirmar)
/ok/:codenoOkPage
/loginno (si hay token → /turno)LoginPage
/turnoauthTurnoPage

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

CheckOK
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

ProhibidoMotivo
npm workspacesAP-06
Commit de .envSecreto
Prometer entrada, escenario-como-hecho, 112 o kanbanMicrocopy duro
Estado RECIBIDO / CURSO / CERRADOVocabulario de PREGÓN
Role OPERADOR / COLORISTA / HOSTEso es PREGÓN / MATIZ / RONDA
Search bar, chat o wizard como homeRompe H-KIOSK
Hero 2-col + 3 cardsAP-12
Pago en kioskS4
GET público de bookings con nombresD9

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)

EntregaEvidencia
Definición producto + ternadocs 00-brief, 01
Personas Iván / Lola / Marta, JTBD, journeydocs 02
IA kiosk-first + chrome S-MINdocs 03
Flujos F-BOOK + F-TURNOdocs 04
Modelo users / rooms / bookings + seeddocs 05
Stack Angular/Nest/Neon/JWT :3021docs 06, 20
Dirección vehicle dashboard + DSdocs 07, 08
Copy Hora ≠ concierto · Sala ≠ escenario · no entradas · ensayar ≠ actuardocs 09
Paper ref 12 UX + 12 UIdocs 00-paper-reference
Suite 00–20 + README + executivecase 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)

ÍtemNotas
Ticket público mínimo { code, roomName, slot }Sigue sin listar otras horas
Cancel CONSERJENo es self-service de banda
Grey de bloques ya pasadosDemo v1 no greyea (smoke siempre posible)
GET /api/meTurno pinta Lola desde API
Rate limit login + POST bookingsAnti stuffing / spam
Playwright S1–S30CI
API URL por environmentDeploy
prefers-reduced-motion verificadoa11y
?slot= deep link a confirmarMust 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)

ÍtemPor qué
Entradas / ConciergoTEMPLE no vende entradas
Escenario / line-upSala ≠ escenario
112 como canalTEMPLE no es 112
Chat + kanban≠ PREGÓN
Cuaderno de fórmulas / Hoy bento≠ MATIZ
Wizard + comparador de fincas≠ ZAGUÁN
Lookbook editorial≠ MARGEN
App nativaFuera de stack daily
Hero 2-col + 3 cardsAP-12

6. Orden de ataque si hay continuidad de código

  1. Contratos 05–06 + seed 05 + smoke 13 (build paralelo)
  2. Web paridad UI-00…11
  3. Ticket público mínimo + rate limit (L+1)
  4. Cancel CONSERJE si hay campo
  5. Evaluar brief L3 (no parche silencioso)

16-interaction-specs.md

16 — Especificación de interacción — TEMPLE

1. Convenciones

TokenValor
Duración corta120–160ms
Easingease-out
Reduced motion0ms
Target≥44×44 (slots kiosk ≥56 preferible)
Pendingcontrol 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

GestoResultado
Primera cargaLoading: 3 tiles panel; aria-busy
200 con 33 salas. Lead: eslogan. 3 datos por tile
200 con 0UI-08 empty
Error 5xx / redUI-09 + Reintentar (repite GET rooms)
Tap tile/sala/:slug
Tap Turno (ghost)/login o /turno si hay token
Hover tile desktopRule 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)

GestoResultado
Primera cargaLoading: 5 celdas; aria-busy
2005 bloques free/taken
0 libresUI-08 + ← Salas
ErrorUI-09 + Reintentar
Tap slot freeSelecciona; abre confirmar (UI-04)
Tap slot takenNo 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)

CampoInteracción
bandNametext · autocomplete organization / name
GestoResultado
Coger horaPOST; pending; no navegar si inválido
Submit inválidoFoco al campo error; no POST
Error redBotón Reintentar; no limpia el nombre
409Banner «Esa hora ya está cogida.»; cierra confirmar; refresca GET :slug
Doble tapIgnorado mientras pending
201Navega /ok/:code con state (sala, slot, banda, code)
Cancelar / EscapeVuelve 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)

GestoResultado
CTA primarioCoger otra /
CopyVisible «Hora cogida no es concierto» + código + «no vende entradas» + «sala ≠ escenario» + «ensayar no es actuar»
RecargaCódigo de URL + copy; sin hidratar GET JWT

Sin confetti. Sin público. Sin «cobrar». Sin escenario que se ilumina.


6. Login (UI-06)

GestoResultado
SubmitPOST login; pending en botón
200Guarda token + user; navega next sanitizado o /turno
401Texto bajo el form; password no se limpia
EnterSubmit
Volver al kiosk/
Primera cargaForm 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)

GestoResultado
Primera cargaLoading: matriz 5×3; aria-busy
200celdas con banda o Libre
0 horasUI-08
ErrorUI-09 + Reintentar
Tap celdaNada Must v1 (no hay ficha). Could L+1: detalle
Hover desktopRule 1px cream; no elevación
Drag-and-dropNo
Tap SalirLimpia storage → /login

AC: banda o Libre visibles sin hover. Cero botones Entradas / 112 / Recibido.


8. Empty (UI-08) · Error (UI-09) · Loading (UI-10)

EstadoInteracción
Empty kioskTitular Fraunces 28 + 1 línea
Empty slotsTitular + 1 línea + ← Salas
Empty turnoTitular + 1 línea
ErrorBanner + Reintentar; foco al banner; no pierde form
Loading kiosk3 tiles panel
Loading slots5 celdas
Loading turno5×3 celdas
409Banner jewel + refresh rejilla

9. Cabecera S-MIN

GestoResultado
Tap wordmark (público)/
Tap wordmark (auth)/turno
Tap Turno (kiosk)/login o /turno
Tap SalirLogout
ScrollCabecera no hide-on-scroll v1

10. Motion

SuperficieSpec
Cambio de rutaFade 160ms (off si reduced-motion)
TilesFade 160ms, stagger ≤30ms (off si reduced-motion)
Slot selectedFilete amber 120ms
SkeletonsEstá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

  1. Un músico en 390px llega de abrir / a ver un código en ≤ 3 taps útiles (sala → hora → Coger).
  2. Ningún submit permite doble POST.
  3. Reduced-motion elimina stagger y slide.
  4. La home no es hero 2-col (AP-12).
  5. En 390 las 3 salas son visibles sin carousel de marca (AP-21).
  6. / no presenta ningún control de cuenta, entradas o kanban.
  7. El loading de kiosk es skeleton de 3 tiles, no un logo de concierto.
  8. El ticket muestra «hora ≠ concierto» y «no vende entradas» sin scroll en desktop.
  9. Lola en 1440 lee Marta Chen en Sala 1 16–18 sin abrir una ficha.
  10. Un 409 refresca la rejilla y no navega a /ok.
  11. Manos en el pasillo: cero gestos que exijan hover o swipe horizontal como único camino.
  12. 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.

RutaPaperRol
/UI-01, UI-02, UI-08, UI-09, UI-10BANDA / Guest
/sala/:slugUI-03, UI-04, UI-11BANDA / Guest
/ok/:codeUI-05BANDA / Guest
/loginUI-06CONSERJE
/turnoUI-07, UI-08, UI-09, UI-10CONSERJE

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)

  1. Abrir / sin token — kiosk público. Leer eslogan La hora, no el concierto. Leer 3 salas (Batería, Combo, Seca) con lead + 3 datos.
  2. Tocar Sala 2 Combo. Ver rejilla: 10–12 / 12–14 / 16–18 cogidas; 18–20 y 20–22 libres. Sin nombres de otras bandas.
  3. Tocar 18–20. Confirmar: nombre Los Yesos. Leer «Hora cogida no es concierto» y «se paga en ventanilla».
  4. Coger hora/ok/TM-XXXX — «Hora cogida no es concierto. TEMPLE no vende entradas.» «Sala ≠ escenario. Ensayar no es actuar.»
  5. Ghost Turno/login. Entrar lola@temple.nave / password123.
  6. /turno — horario 5×3. Sala 1 16–18 Marta Chen. Sala 2 18–20 Los Yesos (tras el POST).
  7. Comprobar que no hay botón Entradas, 112-como-envío ni columnas Recibido / En curso.
  8. Viewport 390: kiosk 3 salas apiladas; rejilla; turno apilado por sala.
  9. Salir/login. / sigue siendo el kiosk.
  10. (Opcional) POST otra vez Combo 18–20 → 409.

Estados en el mismo prototipo

EstadoCómo provocarlo
Empty kiosk0 filas en rooms (entorno de test)
Empty slots0 free en esa sala
ErrorAPI caída / 5xx
Loadingthrottle de red en GET /rooms o /turno
404 sala/sala/palco
409segundo POST al mismo slot
401 turno/turno sin token → login
Kiosk 390390 × 844 en /
Kiosk 14401440 × 900 / (UI-01)
Slots 390390 × 844 /sala/combo (UI-11)
Ticket recargadoF5 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

RequisitoEstadoEvidencia
Diversidad sector/tipo/nivelOKMúsica ensayo L2; no admin pública; no belleza; no L1 consecutivo
Terna S/H/F 0 códigos = N−1 · ≥2 vs N−2OKS-MIN · H-KIOSK · F-BOOK vs PREGÓN S-SIDE · H-CHAT · F-KAN
Day brief + anti-patronesOKdocs/00-day-brief.md (no sobrescrito)
Paper ≥12 UX + ≥10 UIOKUX-count 12 · UI-count 12 · file 01M0HJ2Z7NJSYC0FDMWYSSQBG3
Docs 00–20OKsuite en docs/ + executive + README
JWT CONSERJEOKRole CONSERJE · D-P1-05 · turno cerrado, kiosk público
API + seed + NeonOKcontratos divine-haze-05909195, port 3021, health temple-api
Web tokensOKFraunces + Atkinson Hyperlegible · paleta vehicle dashboard
Kiosk-first (no AP-12 / AP-21)OKUI-01 / docs 03, 07, 08
Hipótesis no fake fieldOKetiquetas en doc 02
Copy ×4 irrenunciableOKdocs 01, 09, 16
Ground G-INKOK#12110F · no G-FOG / G-CHAPEL / G-CONCRETE
No Conciergo / no 112 / no kanban / no chatOKdocs 01, 03, 09

3. Cobertura funcional

Feature briefSpecUI PaperAPIDocs
Home kiosk 3 salasUI-01, UI-02GET rooms03, 04, 16
Rejilla 2 h hoyUI-03, UI-11GET rooms/:slug04, 05
Confirmar nombre de bandaUI-04POST bookings04, 09
Ticket códigoUI-05POST 20104, 09
Login CONSERJEUI-06POST login04, 06
Turno horarioUI-07GET turno03, 04, 16
EmptyUI-08200 []16
ErrorUI-095xx/red/40916
LoadingUI-10pending16, 17
Kiosk / slots mobileUI-02, UI-11misma API04, 16
Design systemUI-0008
Seed 1 + 3 + 8 (8/15)seed05
Health temple-apiGET health05, 06, 20
Unique slot 409UI-09POST 40905, 13

4. Cobertura Paper (literales)

IDNombreEn 00-paper-reference
UX-00Cover
UX-01Stakeholders
UX-02Personas
UX-03JTBD
UX-04Stories
UX-05Journey
UX-06Blueprint
UX-07Site map
UX-08Flujos
UX-09Datos+permisos
UX-10Métricas
UX-11Research
UI-00Tokens
UI-01Kiosk home
UI-02Kiosk mobile
UI-03Slots
UI-04Confirm
UI-05Success
UI-06Login
UI-07Turno
UI-08Empty
UI-09Error
UI-10Loading
UI-11Slots mobile

[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)

EjeScore 1–5Comentario
Diversidad5Kiosk+horas música vs chat+kanban PREGÓN, PWA oficio MATIZ y wizard ZAGUÁN; L2 no L1
Craft visual (spec)4–5Vehicle dashboard + Fraunces/Atkinson + fotos de sala documentadas
Densidad UX docs5Suite L2: tablas, AC, etiquetas S/H/D
Unicidad estructura5R-HY · S-MIN · H-KIOSK · F-BOOK · 0 códigos = N−1
Paper counts512 UX + 12 UI en paper-reference
Honestidad de research5Sin entrevistas inventadas; personas como constructo
Contrato de build5rooms + bookings + JWT CONSERJE · :3021 · temple-api

6. Huecos conscientes (no deuda del L2 del día)

HuecoTratamiento
Código Angular/Nest en paraleloDoc 20 = contrato; no se finge un leftover como estado
Instrumentación analyticsModelo (doc 12); no cifras inventadas
Campo real con músicosPlan en doc 02 §10; no ejecutado
Cancel / grey de pasados / ticket hidratadoL+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ÍtemCapa
D01Definición producto TEMPLE + esloganDocs
D02Day brief diversidad música ensayo L2Docs (preexistente, no pisado)
D03Terna R-HY · S-MIN · H-KIOSK · F-BOOKDocs
D04Personas Iván Mora / Lola Rivas / Marta ChenDocs + Paper ref
D05JTBD + stories MustDocs
D06IA kiosk-first + chrome S-MINDocs
D07Flujos F0–F9 + ACDocs
D08Modelo users / rooms / bookingsDocs
D09Contratos API :3021 · health temple-apiDocs
D10Auth JWT CONSERJE · POST bookings públicoDocs
D11Unique slot + 409 · 401 turnoDocs
D12Kiosk 3 salas + rejilla 5 bloques + confirmarDocs
D13Microcopy ×4 (concierto / escenario / entradas / actuar)Docs
D14North star % bloques sin WhatsAppDocs
D15Tokens vehicle dashboard + Fraunces / AtkinsonDocs
D16Paper UX-00…11 + UI-00…11Docs
D17Suite docs 00–20 + README + executiveDocs
D18Seed 1 CONSERJE + 3 salas + 8 horas 8/15Docs
D19Assets listados (hero + 3 salas)README
D20QA smoke + S1–S30Docs
D21Neon divine-haze-05909195Docs
D22Kiosk 390/1440 + turno horario especificadosDocs
D23Ground G-INK #12110FDocs
D24Rutas reales solo las 5 del encargoDocs
D25Kiosk no filtra bandName ajenoDocs

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ÍtemPrioridadNotas
I01Implementar apps/api + apps/web al contrato TEMPLEP0rooms + bookings + JWT CONSERJE
I02Schema users / rooms / bookingsP0UNIQUE (room_id, day, slot)
I03Seed Lola + 3 rooms + 8 bookings 8/15P0
I04GET rooms público · GET :slug sin bandNameP0
I05POST bookings público + 409P0status CONFIRMED al crear
I06POST login JWTP0lola@temple.nave
I07GET health service: "temple-api"P0puerto 3021
I08GET /api/turno JWTP0401 sin token
I09Auth guard Angular solo /turnoP0/ /sala/:slug /ok/:code públicos
I10Kiosk / slots / ok / login / turnoP0
I11Tokens Tailwind ink/panel/cream/amber + fotosP0Fraunces + Atkinson
I12Smoke curl + buildP0D-P1-06

3. Backlog L+1 (polish)

IDÍtemPrioridadNotas
B01Ticket público mínimo { code, roomName, slot }P1no listar otras horas
B02Cancel CONSERJEP2no self-service
B03Rate limit login + POST bookingsP1anti stuffing / spam
B04Playwright smokeP1CI
B05Skeleton UI-10 en códigoP2
B06GET /api/meP2
B07Grey de bloques pasadosP3demo v1 no greyea
B08API URL por environmentP1deploy
B09Página 404 amigableP3
B10Sessions invalidablesP2
B11?slot= deep linkP3

4. Backlog L3 (requiere brief nuevo)

IDÍtemDependencia
C01Multi-conserje / multi-naveusers + membership
C02Cuenta BANDA + «mis horas»authz · rompe H3
C03Calendario semanalD13 se rompe · brief nuevo
C04Pago / taquilla / entradasmicrocopy se rompe
C05Chat / kanban / 112terna 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

CampoValor
App path/Users/cristian/orca/temple-app
APINestJS · puerto 3021 · prefijo /api
WebAngular standalone · puerto 4200
Packageapps independientes (npm --prefix o pnpm --filter)
DBNeon PostgreSQL · project divine-haze-05909195
Tablasusers, rooms, bookings (+ sessions Should)
AuthJWT Bearer · role CONSERJE (turno); kiosk y POST bookings públicos
DominioUser, Room, Booking
Fecha2026-08-21
GitHubhttps://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

RolEmailPassword
CONSERJElola@temple.navepassword123

Banda / batería: sin cuenta. Cogen hora en /.

3. Schema

Al boot o vía migrate:

  1. CREATE TABLE / migrate de users, rooms, bookings (doc 05). Opcional sessions.
  2. Índices: rooms(slug), bookings(code), bookings(day, slot), users(email). UNIQUE (room_id, day, slot).
  3. Seed idempotente:
    • upsert CONSERJE lola@temple.nave (bcrypt de password123)
    • upsert rooms por slug (bateria, combo, seca)
    • upsert bookings por code (TM-2101TM-2108) con day = hoy Europe/Madrid (o fecha demo documentada)
  4. 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)

TablaContenido
usersCONSERJE Lola
rooms3 salas
bookings8 horas 8/15
sessionsShould: 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 === CONSERJE protege GET turno.
  • Públicos: health, rooms, rooms/:slug, POST bookings, login.

Oficio

MétodoRutaAuthNotas
GET/api/healthNo{ ok: true, service: "temple-api" }
GET/api/roomsNosort_order asc + freeToday / slotsToday
GET/api/rooms/:slugNoslots free / taken sin bandName
POST/api/bookingsNocrea CONFIRMED + code; day = hoy; 409 si unique
GET/api/turnoJWTmatriz 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áginaRutaResponsabilidad
KioskPage/GET rooms, 3 tiles, empty/loading/error
SlotsPage/sala/:slugGET :slug, rejilla, confirmar, POST bookings, 409
OkPage/ok/:codecódigo + copy; state opcional; sin GET JWT
LoginPage/loginform → login → turno
TurnoPage/turnoGET 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ónRazón
Puerto API 3021Evitar colisión con PREGÓN 3020
Tablas rooms / bookingsDominio de ensayo, no chat ni fórmulas
Role CONSERJEEncargo
Health temple-apiEncargo
Kiosk público + turno JWTS2 / H3 / D-P1-05
JSON camelCaseConvenio web serie daily
POST bookings públicoEncargo; banda sin cuenta
Success /ok/:code sin GETD9 enumeración
Slots públicos sin bandNameD9 pasillo
UNIQUE + 409Dos bandas no caben
day = hoy servidorD13; el cliente no elige mañana
Apps independientesAP-06
Home no usa hero 2-colAP-12 / H-KIOSK
Turno = horarioNo F-KAN
Pago fueraS4

7. Variables de entorno

VariableServicioDescripción
DATABASE_URLAPINeon divine-haze-05909195
JWT_SECRETAPIFirma tokens
PORTAPIopcional, 3021
JWT_EXPIRESAPIopcional, default 12h

Web: URL de API en ApiService (default localhost:3021).

8. Smoke de implementación (mínimo)

  1. Schema OK (tablas users, rooms, bookings existen).
  2. GET /api/health 200 { ok: true, service: "temple-api" }.
  3. GET /api/rooms 200 · 3 salas · slugs bateria/combo/seca.
  4. GET /api/rooms/combo 200 · 5 slots · sin bandName.
  5. POST /api/auth/login 200 + accessToken + role=CONSERJE.
  6. GET /api/turno Bearer: 8 taken / 7 free, codes TM-2101…2108, Marta Chen en bateria 16-18.
  7. GET /api/turno sin token 401.
  8. POST /api/bookings { "roomSlug":"combo","slot":"18-20","bandName":"Los Yesos" } sin token 201 status=CONFIRMED.
  9. Segundo POST al mismo slot 409.
  10. 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
1User Lola Rivas / lola@temple.nave / password bcrypt de password123 / role CONSERJE
23 rooms bateria combo seca con covers y size_m2
38 bookings TM-2101…2108 con slots y bandas de doc 05
4Conteos 8 CONFIRMED · 7 libres
5TM-2104 = Marta Chen · bateria · 16-18
6Combo 18-20 libre para el POST de Los Yesos
7Idempotencia: upsert por email / room slug / booking code
8day coherente con «hoy» del turno

11. Alineación case ↔ app

DocEvidencia esperada en código
05 data modelcolumnas y enums
03–04 IA/flowsroutes + controllers
08 DStailwind colors + fontFamily Fraunces/Atkinson
09 contentstrings en templates (microcopy ×4)
00 paperURLs en README case
11 securityGuard 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:

PiezaContrato
Path/Users/cristian/orca/temple-app
Healthtemple-api · puerto 3021
Tablasusers · rooms · bookings
RoleCONSERJE JWT
Rutas/ /sala/:slug /ok/:code /login /turno
Tokensink / 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.