En esta página 00 — Day brief · 2026-08-26 · BOBINA 0%

00-day-brief.md

00 — Day brief · 2026-08-26 · BOBINA

Decisiones ALS-2 BRIEF

CampoValor
Fecha2026-08-26
NombreBOBINA
ComplejidadNivel 1 (no L2 consecutivo tras LOMO)
SectorCultura / cineclub de barrio (Vallecas)
TipoCartelera feed de sesiones + petición de butaca + mesa PROGRAMADOR JWT
PlataformaWeb responsive (feed en el móvil · mesa en el portátil de la asociació)
RegistroR-IN — dock flotante + feed sobre foto a sangre
ShellS-DOCK — dock fijo: Cartelera · Pedir · Mesa
HomeH-FEED foto-led Pliego — still a sangre + cronología de noches
FlujoF-STORY — cada sesión es un relato (noche + película + butacas) y luego el CTA
Por qué no LOMONo S-CMD / H-DATA / F-LEAD; no archivo; no mineral; no mesa de ejemplares
Por qué no ONDANo radio; no H-GALLERY; no S-RAIL
Por qué no ATRIONo museo CMS L3; BOBINA es un cineclub de 4 noches, no una pinacoteca

Terna unicidad

R-IN · S-DOCK · H-FEED · F-STORY

0 códigos iguales a N−1 (LOMO: R-CL · S-CMD · H-DATA · F-LEAD).
≥2 distintos vs N−2 (ONDA: R-HY · S-RAIL · H-GALLERY · F-SEARCH) y N−3 (RAMAL).

S-DOCK, H-FEED y F-STORY no están en los últimos 5.
R-IN cumple la mezcla de 4 días (LOMO R-CL, ONDA R-HY).

Ground (CRON §5.6)

  • Familia: G-VELVET
  • Hex: #1A1210
  • Por qué: terciopelo de butaca a oscuras, no caliza de sala (LOMO), no cinta de portería (ONDA), no hielo de mástil (RAMAL), no tablero de conserje (TEMPLE), no niebla highlighter (PREGÓN).

Mood visual (Paper)

  • Candidatos: nocturnal/neón de cine (primer instinto cartelera), chapel, rusted, candlelit, subterranean
  • Elegido: candlelit — no el primer instinto neón de multiplex. Un cineclub de barrio se enciende con apliques de latón, no con LED de Cinesa.
  • Paleta:
    • #1A1210 terciopelo (ground)
    • #F4EDE4 crema de ficha
    • #241C18 asiento / card
    • #C4A574 latón (mark)
    • #8A7A6E mute
    • #9A3B2F oxblood (sello, poco)
  • Tipo: Cormorant Garamond display · Manrope UI

Home foto-led (D-P1-09)

UI-01 = Pliego: still de la sala a sangre (≥40 % del recorte 16/10) + feed de 4 sesiones encima. No tabla. No H-DATA. Cuota ≥3 de últimos 6: DERIVA, PLIEGO, LOMO (retrofit split), BOBINA.

Alcance L1 must

  1. Home feed foto-led: 4 sesiones
  2. Relato de sesión (noche + película + butacas)
  3. Pedir butaca (pedir ≠ entrada Cinesa)
  4. Success con copy duro
  5. Login JWT PROGRAMADOR
  6. Mesa de noches + pedidos
  7. Empty / error / loading / mobile feed
  8. ≥12 UX + ≥10 UI

Microcopy duro

  • Pedir butaca ≠ entrada Cinesa. No se compra un ticket de multiplex.
  • Sesión ≠ estreno. No es el circuito comercial.
  • Cartelera ≠ Filmin. No hay VOD ni archivo en streaming.
  • BOBINA no es los cines del centro.

Supuestos

  • S1: El cineclub programa 2–4 noches/semana en el slice; demo 4. [SUPUESTO]
  • S2: El vecino pide butaca sin cuenta. JWT solo PROGRAMADOR. [SUPUESTO]
  • S3: Proyeccionista y barra fuera del producto. [SUPUESTO]
  • S4: Sin taquilla Cinesa, sin Filmin, sin GPS, sin chat. [DECISIÓN]

Hipótesis

IDSeñal
H1Un feed de noches reduce «¿qué echan hoy?» por WhatsApp
H2Separar butaca de entrada Cinesa evita el conflicto con el multiplex
H3Cuatro sesiones bastan; no hace falta un VOD

Seed demo

CódigoTítuloNocheButacasEstado
BOB-2601El espíritu de la colmenajue 27 ago 20:0012ABIERTA
BOB-2602Los golfosvie 28 ago 21:008ABIERTA
BOB-2603Cría cuervossáb 29 ago 19:300COMPLETA
BOB-2604El surdom 30 ago 18:0014ABIERTA

Títulos de cine español clásico son catálogo demo. No es una programación real ni un acuerdo con Filmoteca. [SUPUESTO de cartelera]

JWT

marta@bobina.cine / password123 · rol PROGRAMADOR · API :3026

00-paper-reference.md

Paper reference · BOBINA

URLhttps://app.paper.design/file/01M0YE7DABVQNCPYK4JQPCSEEQ
File ID01M0YE7DABVQNCPYK4JQPCSEEQ

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 Cartelera feed foto-led · UI-02 Cartelera mobile · UI-03 Sesión · UI-04 Sesión mobile · UI-05 Pedir · UI-06 Success · UI-07 Login · UI-08 Mesa PROGRAMADOR · UI-09 Empty · UI-10 Error+Loading · UI-11 Dock

UX process (prefijo UX- · mínimo 12)

IDNombreContenido
UX-00CoverBOBINA · «La butaca, no la taquilla.» · R-IN · S-DOCK · H-FEED · F-STORY · L1 cineclub · candlelit · 2026-08-26
UX-01StakeholdersPROGRAMADOR Marta, VECINO Luis, proyección fuera, Filmoteca fuera
UX-02PersonasMarta Ruiz 41 · Luis Navarro 34 · Inma Peña 68 (docs)
UX-03JTBDJob «saber qué noche hay butaca sin preguntar por WhatsApp»
UX-04StoriesMust: feed, relato, pedir, login, mesa, estados
UX-05JourneyCalle → still de sala → Cría cuervos completa → El sur → pedir butaca
UX-06BlueprintFrontstage sala · backstage Neon/JWT
UX-07Site map/ feed · /sesion/:code · /pedir/:code · /ok/:code · /login · /mesa
UX-08FlujosF-STORY público; mesa PROGRAMADOR
UX-09DatosUser PROGRAMADOR · Sesión; JWT en /mesa
UX-10MétricasNorth star % de noches con butaca pedida antes de las 18:00
UX-11ResearchComprobado / supuesto / hipótesis / decisión

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

IDNombreFlujo
UI-00TokensDS candlelit: velvet, brass, oxblood
UI-01Cartelera feedPliego: still a sangre + feed de 4 noches · recorte 16/10
UI-02Cartelera mobile390 · dock
UI-03SesiónRelato El espíritu de la colmena
UI-04Sesión mobile390
UI-05PedirForm butaca
UI-06SuccessPedida. Butaca ≠ entrada Cinesa
UI-07LoginJWT PROGRAMADOR
UI-08Mesa PROGRAMADORLista + pedidos
UI-09EmptySin noches
UI-10Error+LoadingRed / skeletons
UI-11DockS-DOCK Cartelera · Pedir · Mesa

Mapeo Paper → Angular

ArtboardRutaComponente
UI-01 Cartelera/CarteleraPage
UI-03 Sesión/sesion/:codeSesionPage
UI-05 Pedir/pedir/:codePedirPage
UI-06 Success/ok/:codeOkPage
UI-07 Login/loginLoginPage
UI-08 Mesa/mesaMesaPage

01-project-definition.md

01 — Definición de proyecto — BOBINA

1. Identidad

CampoValor
NombreBOBINA
SignificadoBobina es el rollo que se proyecta en sala, no el ticket que se compra en multiplex ni el stream que se mira en casa. Se entra a la cartelera; se sale habiendo pedido butaca.
Eslogan«La butaca, no la taquilla.»
Una fraseCartelera feed foto-led de noches + relato de sesión + petición de butaca + mesa PROGRAMADOR JWT.
SectorCultura / cineclub de barrio (Vallecas, Madrid)
TipoWeb L1 — feed H-FEED Pliego + dock S-DOCK + story F-STORY + mesa JWT — Nivel 1, vertical slice de cineclub
PlataformaWeb responsive (feed en el móvil · mesa en el portátil de la asociación)
Mercado demoEspaña · Madrid · Vallecas (un cineclub de barrio, no los cines del centro)
Idiomaes-ES
Fecha caso2026-08-26
TernaR-IN · S-DOCK · H-FEED · F-STORY

[COMPROBADO] Nombre, terna, nivel, sector, ground y paleta salen de docs/00-day-brief.md.
[SUPUESTO de cartelera] Vallecas / Erice / Saura es atrezzo de mercado, no la programación real de un cineclub municipal.

Tras LOMO (L2 archivo, 2026-08-25) el día elige L1 cineclub, no otro L2 consecutivo. N−1 es LOMO. [DECISIÓN]

2. Problema

Principal (hipótesis de diseño)

[HIPÓTESIS] El vecino de Vallecas no necesita Filmin ni la taquilla del centro: necesita saber qué noche hay butaca sin preguntar por WhatsApp. Hoy eso vive en un grupo, un cartel en el portal y una expectativa de «entrada». La cartelera se lee como Cinesa; pedir butaca se lee como comprar ticket; el producto se lee como los cines del centro. [SUPUESTO] Un cineclub programa 2–4 noches/semana; no opera un VOD ni un estreno comercial.

Secundarios

ProblemaQuién lo sufreEfecto
«¿Qué echan hoy?» por WhatsAppVECINO (Luis)Pregunta, espera, se pierde la noche
Pedir butaca se lee como entrada CinesaVECINO + MartaEsperan precio, fila, código QR de multiplex
La home se lee como FilminLuisEsperan catálogo VOD, play, archivo en streaming
Pedir se lee como estrenoLuis + InmaEsperan cartelera comercial, fecha de estreno
La mesa PROGRAMADOR se lee como kanbanPROGRAMADOR (Marta)Esperan Recibido / En curso / Cerrado
El dueño pide VOD y taquilla el día 1AsociaciónEl L1 se vuelve Cinesa + Filmin

Supuestos (no investigación primaria propia)

  • S1: El cineclub programa 2–4 noches/semana en el slice; demo 4. [SUPUESTO]
  • S2: El vecino pide butaca sin cuenta. JWT solo PROGRAMADOR. [SUPUESTO]
  • S3: Proyeccionista y barra fuera del producto. [SUPUESTO]
  • S4: Sin taquilla Cinesa, sin Filmin, sin GPS, sin chat. [DECISIÓN]

Hipótesis de producto

IDHipótesisSeñal de validación (futura)
H1Un feed de noches reduce «¿qué echan hoy?» por WhatsApp% de visitas a / que terminan en POST /pedir
H2Separar butaca de entrada Cinesa evita el conflicto con el multiplex↓ «pensé que compraba entrada»; copy visible en success
H3Cuatro sesiones bastan; no hace falta un VOD0 Filmin; Marta decide el hoy sin archivo streaming

No se afirman estadísticas de cineclub inventadas. Todo lo anterior es razonamiento de diseño etiquetado.

3. Propuesta de valor

ParaValor
VECINO (Luis Navarro)Ve 4 noches en el feed, abre El sur, pide butaca, se lleva el código. Nadie le pide cuenta ni ticket.
PROGRAMADOR (Marta Ruiz)Ve la mesa de noches, lee estados y pedidos. No mueve columnas. No vende entradas.
VECINA MAYOR (Inma Peña)Fuera del login; la documentación y a11y la contemplan (contraste cream/velvet, targets, copy legible).
Cineclub BOBINAUna superficie mínima: cartelera + relato + mesa, sin Cinesa y sin Filmin.

No es BOBINA

ExcluidoPor qué
Taquilla Cinesa / ticket / QR multiplexPedir butaca ≠ entrada Cinesa
Filmin / VOD / archivo en streamingCartelera ≠ Filmin
Estreno comercial / circuitoSesión ≠ estreno
Cines del centro / multiplexBOBINA no es los cines del centro
Catálogo completo / miles de títulosH3 · S1
Chat de vecinos / kanbanEso fue PREGÓN (H-CHAT / F-KAN)
Quiosco de horas / bloques de 2 hEso fue TEMPLE (H-KIOSK / F-BOOK)
Galería de cubiertas / archivo de radioEso fue ONDA (H-GALLERY / F-SEARCH)
Mesa de ejemplares + comandoEso fue LOMO (H-DATA / S-CMD / F-LEAD)
Portada de nodos + checklist de altaEso fue RAMAL (H-FULL / F-ONB)
Hero 2-col + 3 cards de «tu cine»Anti-patrón AP-12; contradice H-FEED Pliego
App de 40.000 títulos y CMSL1 compacto, no Filmoteca

4. Objetivos

Negocio / caso de estudio

  • Demostrar vertical slice L1 cineclub de barrio con Sesión + pedido + JWT PROGRAMADOR.
  • Portfolio coherente: Paper (12 UX + 12 UI) + docs + app runnable.
  • Terna R-IN · S-DOCK · H-FEED · F-STORY frente a LOMO (cmd/datos/lead), ONDA (rail/galería/archivo) y RAMAL (split/portada/alta).
  • No encadenar otro L2 tras LOMO. [DECISIÓN]

Usuario

RolObjetivo medible en demo
VECINOVer 4 noches, tocar El sur, pedir butaca y ver el success en < 90 s, sin cuenta
PROGRAMADOREntrar a mesa, ver 4 sesiones, leer BOB-2604 y los pedidos en < 45 s
VECINA MAYORNo encuentra login; a11y y docs la contemplan; no es rol de sistema

No objetivos v1 (explícitos)

  • Taquilla, precio, pago, QR de multiplex
  • Filmin, VOD, play, archivo en streaming
  • Estreno comercial, cartelera de circuito
  • Chat, kanban, columnas Recibido / En curso
  • Cuenta de vecino, socio, newsletter
  • GPS, mapa de salas, horario de Filmoteca
  • Multi-sede, multi-programadora
  • App nativa ni notificaciones push
  • Rol proyeccionista / barra autenticado
  • Ejemplares, BIBLIO, comando (LOMO es otro día)
  • Programas, repeticiones, CONDUCTOR (ONDA es otro día)
  • Nodos, altas, vocal (RAMAL es otro día)

5. Roles y permisos (resumen)

AcciónAnónimo (vecino)PROGRAMADORVECINA MAYOR
Ver cartelera /Sin cuenta; usa la pública
Ver relato /sesion/:code
Ver form /pedir/:codeSí (no es el job)
POST pedir butacaSí (no es el job)Sí (mismo form público)
Ver success /ok/:code (código en URL)
Ver mesa /mesaNo (401 / redirect)No
GET /api/mesa401
Ver lista de pedidosNoSí (mesa)
Vender entrada CinesaNo (no existe)NoFuera
Proyectar / barraCopy: fueraCopy: fueraOficio fuera de app

[DECISIÓN] Un solo rol autenticado: PROGRAMADOR. El vecino no es un usuario del sistema: es autor/autora de un pedido. Inma 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 noches ABIERTA con ≥1 pedido antes de las 18:00Oficio de sala, no pageviews
Activación vecino1.er POST /pedir con codeH1
Integridad de expectativaReclamaciones «¿compro entrada?» / «¿es Filmin?» / «¿es estreno?»H2 + microcopy
Integridad de authGET /api/mesa sin token → 401; POST /api/sesiones/:code/pedir sin token → 201Feed público + mesa PROGRAMADOR cerrada
SaludError rate API sesiones / pedidos4xx/5xx

7. Alcance funcional v1 (L1)

MóduloIncluido
Cartelera feedGET /api/sesiones · still a sangre + 4 noches
RelatoGET /api/sesiones/:code · título, director, noche, butacas, blurb
PedirPOST /api/sesiones/:code/pedir → success; butaca ≠ Cinesa
AuthPOST /api/auth/login → JWT PROGRAMADOR
Mesa PROGRAMADORGET /api/mesa JWT · lista + pedidos, no kanban
Estados UIEmpty (0 noches), loading skeleton, error de red
MobileFeed ~390px · dock Cartelera · Pedir · Mesa · targets ≥44px
Seed1 PROGRAMADOR, 4 sesiones (3 ABIERTA, 1 COMPLETA)
SaludGET /api/health{ ok: true, service: "bobina-api" }

8. Criterios de aceptación de producto

  1. / es el feed foto-led Pliego (still a sangre + 4 noches). No pide cuenta. No es un hero 2-col + 3 cards. No es una mesa de datos.
  2. Un vecino puede ver 4 sesiones, tocar El sur, pedir butaca y obtener success en /ok/BOB-2604.
  3. /ok/:code dice explícitamente que pedir butaca no es entrada Cinesa y que sesión no es estreno.
  4. La UI dice explícitamente que cartelera no es Filmin y que BOBINA no es los cines del centro.
  5. Sin token, GET /api/mesa responde 401. POST /api/sesiones/:code/pedir y GET /api/sesiones son públicos.
  6. Un POST de pedir no crea user, no cobra, no abre Filmin, no mueve kanban.
  7. Un PROGRAMADOR inicia sesión y ve 4 sesiones (3 ABIERTA, 1 COMPLETA) en el seed.
  8. El tablero autenticado es una mesa de lista + pedidos. No es un kanban de 3 columnas. No es un split lista | ficha.
  9. Fotos reales en las cubiertas seed (assets sesiones/*).
  10. Chrome S-DOCK: Cartelera · Pedir · Mesa. Feed sin top-nav de marketing y sin comando de archivo.
  11. Rutas solo las del doc 03. No existen /buscar, /lomo, /programa, /hoy JWT de ONDA, /nodos, /alta.
  12. GET /api/health devuelve service: "bobina-api" (no lomo-api, no onda-api).
  13. El feed público no muestra nombres de otros vecinos; la mesa PROGRAMADOR sí muestra pedidos con nombre.
  14. Cría cuervos (BOB-2603) aparece COMPLETA con 0 butacas; no se puede pedir.

9. Stack y artefactos

CapaDetalle
FrontendAngular + Tailwind · puerto 4200
BackendNestJS · puerto 3026
DBNeon PostgreSQL · project tiny-feather-31905339
AuthJWT (PROGRAMADOR)
DiseñoPaper 01M0YE7DABVQNCPYK4JQPCSEEQ
Repo app/Users/cristian/orca/bobina-app/ · GH Criscode2022/bobina-app
Packagepnpm

[COMPROBADO] Puerto, Neon, Paper file ID y path de app constan en el encargo.
El código se escribe en paralelo a esta suite. Este doc es el contrato. No se espera al rewrite.

10. Riesgos y mitigaciones

RiesgoImpactoMitigación v1
Expectativa de Cinesa«¿Compro la entrada?»Copy «Pedir butaca ≠ entrada Cinesa»
Expectativa de FilminPlay, VOD, archivoCopy «Cartelera ≠ Filmin»
Expectativa de estrenoCircuito comercialCopy «Sesión ≠ estreno»
Expectativa de centroMultiplex, taquillaCopy «BOBINA no es los cines del centro»
Expectativa de kanbanRecibido / En cursoLista + pedidos, no columnas de estado
Leftover LOMOejemplares, BIBLIO, lomo-apiContrato BOBINA; health bobina-api; 0 copy de archivo
Leftover ONDAprogramas, CONDUCTOR, radioDominio sesiones + pedidos + PROGRAMADOR
VOD el día 1Alcance L4 disfrazadoH3: cuatro noches
Cuenta de vecinoRompe S2Sin signup; POST público con nombre de sala
Home percibida como landing de cinePérdida de H-FEED / AP-12Pliego still + feed; no hero 2-col
Home percibida como mesa de datosConfundir con LOMOH-FEED; no métricas tabulares ni comando
Confundir con ONDA (galería + archivo)Expectativa de cubierta / repeticiónFeed de noches; no cubiertas 16/10 de radio
Confundir con TEMPLE (kiosk + horas)Expectativa de bloques de 2 hPedir butaca de una sesión; no slots
0 sesionesFeed vacío sin oficioEmpty «Aún no hay noches.»
WhatsApp paraleloH1 no se mideNorth star etiquetada como modelo
Brass como texto de párrafoContraste WCAGBrass pinta CTA/foco; cream escribe sobre velvet

11. Glosario

TérminoDefinición en BOBINA
BobinaRollo / proyección en sala; el producto, no el ticket ni el stream
SesiónNoche programada (sesiones); no es un estreno comercial
CódigoBOB-XXXX; identifica la sesión
ButacaPlaza física en sala; no es entrada Cinesa
CarteleraSuperficie H-FEED pública de noches; feed sobre still
Mesa (PROGRAMADOR)Superficie JWT de Marta (lista + pedidos, no kanban)
PedidoPOST 201; no significa ticket ni Filmin
SuccessCódigo (BOB-XXXX); no es un QR de multiplex
AbiertaEstado ABIERTA; quedan butacas
CompletaEstado COMPLETA; 0 butacas restantes
DockChrome S-DOCK: Cartelera · Pedir · Mesa
PROGRAMADORUsuario autenticado que opera la mesa
VECINOAutor/autora del pedido; no tiene fila en users
VECINA MAYORPersona de docs / a11y; fuera del login
CinesaMultiplex; fuera. Pedir ≠ entrada
FilminVOD; fuera. Cartelera ≠ Filmin
CentroCines del centro; fuera. BOBINA no es el centro
CandlelitMood: velvet + latón, no neón de multiplex
GroundTerciopelo #1A1210
CreamTexto / ficha #F4EDE4
CardAsiento #241C18
BrassLatón #C4A574
Mute#8A7A6E
OxbloodSello #9A3B2F, poco
PliegoHome foto-led: still a sangre + feed overlay

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

IDDecisiónAlternativa descartada
D1Home = feed foto-led Pliego (H-FEED)Hero 2-col + 3 cards (AP-12) · mesa de datos (LOMO) · galería (ONDA) · search-first
D2Shell dock Cartelera · Pedir · Mesa (S-DOCK)Comando de archivo · rail de radio · split mesa · kiosk mínimo
D3Registro inmersivo de sala a oscuras (R-IN)Neón de multiplex (primer instinto) · mineral LOMO · signage ONDA
D4Flujo F-STORY (relato → CTA)F-LEAD, F-SEARCH como home, F-BOOK, F-KAN, F-ONB
D5Mood candlelitNeón de cine (primer instinto), chapel, rusted, subterranean
D6Un rol autenticado PROGRAMADORMulti-rol proyeccionista / vecino / barra
D7Status ABIERTA / COMPLETAKanban de 3 columnas; «vendida»; «en Filmin»
D8Vecino sin cuentaSignup, socio, carnet de cineclub
D9Feed público no lista nombres de vecinosTablero público enumerable
D10POST público de pedir con nombre de salaFormulario de DNI + pago + ticket
D11Ground G-VELVET #1A1210G-STONE, G-SIGN, G-ICE, G-INK, G-FOG
D12Success en /ok/:codeToast único sin pantalla
D13Relato en /sesion/:code antes del formPOST oculto en la tarjeta del feed (rompería F-STORY)
D14Mesa PROGRAMADOR = lista + pedidos, no kanban ni splitRecibido / En curso / Cerrado; lista | ficha RAMAL
D15Feed público + mesa JWT (no auth-first total)Todo cerrado (rompería S2) · todo abierto (rompería mesa)
D16Sin taquilla / FilminPrecio + QR + play
D17Leftover LOMO no es el productoMantener ejemplares / BIBLIO / lomo-api
D18Health bobina-api · puerto 3026leftover lomo-api · :3025

13. Relación con el día anterior

CaseTernaPor qué BOBINA no lo copia
LOMO (N−1)R-CL · S-CMD · H-DATA · F-LEADNo archivo, no ejemplares, no comando, no BIBLIO, no mesa de datos
ONDA (N−2)R-HY · S-RAIL · H-GALLERY · F-SEARCHNo radio, no cubiertas, no repetición, no CONDUCTOR, no rail
RAMAL (N−3)R-CL · S-SPLIT · H-FULL · F-ONBNo telecom, no nodos, no altas, no vocal, no split
TEMPLE (N−4)R-HY · S-MIN · H-KIOSK · F-BOOKNo kiosk, no horas, no concierto; butaca ≠ coger sala de ensayo
PREGÓN (N−5)R-IN · S-SIDE · H-CHAT · F-KANComparte R-IN; no clona chat ni kanban. BOBINA no es 112

[COMPROBADO] El brief fija terna R-IN · S-DOCK · H-FEED · F-STORY. 0 códigos iguales a N−1 (LOMO). ≥2 distintos vs N−2 (ONDA) y N−3 (RAMAL). S-DOCK, H-FEED y F-STORY no están en los últimos 5. Ground G-VELVET #1A1210, no G-STONE ni G-SIGN.

02-ux-research-strategy.md

02 — Estrategia de investigación UX — BOBINA

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 del cineclubModelado de stakeholders + personas§3–4
Definir job «saber qué noche hay butaca sin preguntar por WhatsApp»JTBD + stories Must§5–6
Mapear fricción WhatsApp / Cinesa / Filmin → cartelera feedJourney + service blueprint§7–8
Traducir a requisitos L1 feed + relato + pedir + mesaMatriz hallazgo → requisito → feature§9

2. Fuentes y límites

Fuentes admisibles (secundarias / operativas)

  • Conocimiento general de cineclubs de barrio (cartel en el portal, grupo de WhatsApp, butacas limitadas, programadora que elige 2–4 noches, proyección fuera del producto día 1).
  • Analogía operativa con superficie pública + panel JWT de la serie daily.
  • Restricciones ALS-2: no taquilla Cinesa, no Filmin, no estreno comercial, no archivo de lomos, no radio, no nodos/altas, no kiosk de horas.

Límites éticos de verdad

ProhibidoPermitido
«El 62% de vecinos de Vallecas pregunta por WhatsApp qué echan» sin fuente«[SUPUESTO] Luis abre la cartelera desde el móvil»
Citas de entrevistas ficticias como campo realQuotes de persona etiquetadas como constructo de diseño
Volumen medido «23 butacas/semana de El sur» como KPI de mercadoSesiones de seed de producto, etiquetadas como demo
Programación oficial de un cineclub de Vallecas 2026Sesiones de seed; Marta, Luis e Inma son personas de diseño
«Luis existe y nos dijo…»Luis Navarro es persona de diseño

3. Stakeholders

StakeholderInfluenciaInterésNecesidad principal
PROGRAMADOR (Marta)AltaMuy altaVer noches y pedidos sin kanban ni Filmin
VECINO (Luis)Alta en la butacaMuy altaSaber qué noche hay butaca, sin cuenta
VECINA MAYOR (Inma)Media formal, baja en producto día 1AltaLeer la cartelera con contraste y targets; sin login forzado
Asociación / cineclub de barrioAlta formalAltaQue se vea qué hay esta semana; que no se confunda con Cinesa ni Filmin
Cinesa / multiplexCompetencia / analogía falsaFuera de alcance; no clonar taquilla
Filmin / VODCanal paralelo / analogía falsaFuera; Cartelera ≠ Filmin
Filmoteca / cines del centroAnalogía falsa de circuitoFuera; BOBINA no es el centro
LOMO / sala de lecturaAnti-patrón N−1Fuera; no ejemplares, no BIBLIO, no comando
ONDA / radioAnti-patrón N−2Fuera; no programas, no CONDUCTOR, no antena
Grupo de WhatsApp del barrioCanal paraleloNo es el backoffice; H1 apunta a reducirlo

Mapa de poder (resumen)

  • Decisor de adopción: la asociación (quién pone las noches) y, en uso diario, Marta (quien mira pedidos).
  • Usuario frecuente de pedir butaca: VECINO (feed + relato + form, sin cuenta).
  • Usuario frecuente de oficio: PROGRAMADOR (mesa /mesa).
  • Riesgo de rechazo: si el success parece un ticket; si la tarjeta parece un título de Filmin; si hay que crear cuenta; si la mesa parece un kanban; si el feed parece un estreno comercial.

4. Personas

P1 — Marta Ruiz · PROGRAMADOR

CampoDetalle
Edad / contexto41 años; programa el cineclub en Vallecas; mesa de noches, no de taquilla
DigitalFluida en desktop de asociación; la cartelera pública no es su herramienta principal, pero la mira
GoalsVer qué noches están abiertas, cuáles completas, quién ha pedido butaca
PainsWhatsApp a deshora; «¿compro la entrada?»; un kanban que no es su oficio; un VOD que no es su job de hoy
Quote de diseño«Quiero ver las noches. No una taquilla y no un Filmin.»
Email demomarta@bobina.cine / password123

Escenario: Entra a /login, abre /mesa, lee BOB-2604 El sur ABIERTA, ve los pedidos. El copy dice que pedir butaca no es entrada Cinesa.

[COMPROBADO] Nombre, edad, email demo y rol salen del encargo.

P2 — Luis Navarro · VECINO

CampoDetalle
Edad / contexto34 años; vive en Vallecas; va al cineclub cuando hay butaca; no quiere «otra cuenta de cine»
DigitalMóvil desde el portal o el sofá; no se hace socio si puede evitarlo
GoalsVer qué echan esta semana; abrir el relato; pedir butaca; llevarse un código
PainsEl WhatsApp dice «creo que queda sitio el domingo»; abre Filmin; le venden un ticket; cree que es un estreno
Quote de diseño«Solo quiero una butaca para esta noche. No me hagas un ticket.»

Escenario: Abre / en el móvil, ve Cría cuervos COMPLETA, toca El sur ABIERTA, pide butaca, lee «pedir butaca ≠ entrada Cinesa» y el código BOB-2604.

[COMPROBADO] Nombre, edad y gesto (vecino, 34, pide sin cuenta) salen del encargo. Es constructo de diseño, no entrevistado. [DECISIÓN]
Luis no tiene fila en users. [DECISIÓN]

P3 — Inma Peña · VECINA MAYOR (docs / a11y)

CampoDetalle
Edad / contexto68 años; vecina de Vallecas; lee la cartelera con calma; contraste y tamaño importan
DigitalNo tiene login en el slice L1; usa la superficie pública si el contraste y los targets aguantan
GoalsEntender qué noche hay, sin mistificarse con Cinesa ni Filmin
PainsTexto mute sobre velvet; botones pequeños; copy de multiplex
Quote de diseño«Si no leo la noche, no voy. No me hagáis un ticket.»

[COMPROBADO] Nombre, edad y exclusión de login salen del encargo. [DECISIÓN] no hay cuenta de Inma en v1; a11y la contempla en docs 10.

5. JTBD

Job principal (vecino)

Cuando quiero saber qué noche hay butaca, quiero ver la cartelera y pedir plaza sin preguntar por WhatsApp, para dejar constancia en la asociación sin que eso signifique ticket, cuenta ni Filmin.

Job principal (programadora)

Cuando hay noches abiertas y pedidos nuevos, quiero ver la lista de noches y los pedidos, para mover el oficio del cineclub sin un kanban ni una taquilla.

Jobs que BOBINA no hace

JobPor qué no
Comprar entrada de multiplexPedir butaca ≠ entrada Cinesa · S4
Ver un VOD / archivo en streamingCartelera ≠ Filmin
Ir a un estreno comercialSesión ≠ estreno
Sustituir a los cines del centroBOBINA no es los cines del centro
Pedir mesa de un lomo≠ LOMO
Coger hora de ensayo≠ TEMPLE
Pedir repetición de un programa≠ ONDA
Pedir nodo / alta de bloque≠ RAMAL

6. Stories Must (v1)

IDComoQuieroPara
US-01VecinoVer feed foto-led de 4 nochesDistinguir cartelera de Filmin / Cinesa
US-02VecinoAbrir relato (noche + película + butacas)Saber si está abierta o completa
US-03VecinoPedir butaca y ver success BOB-XXXXDejar constancia, no comprar ticket
US-04ProgramadoraEntrar con JWTAbrir la mesa de pedidos
US-05ProgramadoraVer lista de noches + pedidosOficio sin kanban
US-06AmbosVer empty / error / loadingNo quedarse en blanco
US-07VecinoUsar el dock en 390Cartelera · Pedir · Mesa sin hamburger

Could (fuera de L1): login de Inma, pago, VOD, chat, cuenta de vecino, Filmoteca.

7. Journey (resumen)

  1. Luis abre /. Ve still a sangre + feed de 4 noches. Cría cuervos COMPLETA; El sur ABIERTA. [H1]
  2. Toca Cría cuervos → /sesion/BOB-2603. Lee 0 butacas, COMPLETA. CTA disabled.
  3. Vuelve / toca El sur → /sesion/BOB-2604. Lee 14 butacas, ABIERTA. Copy irrenunciable.
  4. Toca Pedir butaca → /pedir/BOB-2604. Escribe su nombre. POST → /ok/BOB-2604. Lee las cuatro oposiciones.
  5. Marta entra a /login/mesa. Lista + pedidos.
  6. Lee BOB-2604 y el pedido de Luis. Copy: butaca no es entrada Cinesa.

Backstage: Nest + Neon + JWT. Proyeccionista y barra no entran. No hay Filmin. No hay Cinesa.

8. Blueprint (resumen)

CapaQué pasa
Frontstage (sala / calle)Feed Pliego en móvil. Relato. Form pedir. Success. Dock.
Backstage (asociación)Marta mira /mesa. Proyección y barra están fuera de app. La bobina física es oficio, no VOD.
SoporteNest · Neon tiny-feather-31905339 · JWT PROGRAMADOR · Paper candlelit

9. Matriz hallazgo → requisito → feature

Hallazgo (etiquetado)RequisitoFeature v1
[HIPÓTESIS H1] Feed de noches reduce WhatsApp4 noches en fold sobre still/ H-FEED Pliego
[HIPÓTESIS H2] Butaca ≠ Cinesa evita el multiplexCopy irrenunciable + POST que no cobra/pedir/:code + /ok/:code
[HIPÓTESIS H3] Cuatro sesiones bastanSin VODSeed 4 · no Filmin
[SUPUESTO S2] Sin cuenta de vecinoPOST públicoPOST /api/sesiones/:code/pedir
[SUPUESTO S3] Una programadoraUn rol JWTPROGRAMADOR
[DECISIÓN S4] Sin Cinesa / Filmin / GPS / chatNo pago, no play, no mapa, no hiloFuera de alcance

10. Preguntas que este case no responde

  • ¿Cuántas butacas reales se piden en Vallecas en 2026?
  • ¿Qué cineclub opera El espíritu de la colmena?
  • ¿Luis preferiría el WhatsApp?
  • ¿Inma necesita un modo tipográfico mayor permanente?
  • ¿Marta confirmaría pedidos antes de las 18:00 de verdad?

Esas preguntas piden campo. Aquí hay un vertical slice de diseño, no un estudio.

11. Cierre

Investigación = modelado etiquetado + restricciones ALS-2.
No hay entrevistas inventadas.
Paper UX-00…11 documenta el mismo arco. [COMPROBADO] inventario en 00-paper-reference.md.

03-information-architecture.md

03 — Arquitectura de información — BOBINA

1. Principios de IA

PrincipioAplicación
Feed firstLa home es still a sangre + 4 noches. No hay landing de marca por delante. No hay mesa de datos.
Público / mesaLuis pide butaca sin cuenta; Marta entra con JWT
Feed → relato → form → successProfundidad 3 desde la cartelera hasta el código (F-STORY)
Cada sesión es un relatoF-STORY: noche + película + butacas antes del CTA
Mesa PROGRAMADOR = lista + pedidosUna columna + recuento; no kanban, no split lista | ficha
Lenguaje de dominioSesión, butaca, noche, pedido, mesa — no «ticket», «VOD», «lomo», «ejemplar»
Pedir no es comprarEl success no tiene precio ni QR de multiplex
Cartelera no es FilminNo hay play, no hay archivo en streaming
Chrome de oficioS-DOCK Cartelera · Pedir · Mesa; feed sin top-nav de marketing

2. Sitemap

/                                      Cartelera feed pública (Pliego)                 H-FEED
/sesion/:code                          Relato de sesión                                F-STORY · público
/pedir/:code                           Form pedir butaca                               público
/ok/:code                              Success post-pedido                             público
/login                                 Login JWT PROGRAMADOR                           público
/mesa                                  Lista + pedidos                                 auth
/**                                    → redirect /

Árbol por audiencia

AudienciaNodos relevantes
VECINOCartelera → Sesión → Pedir → Ok. No ve /mesa
PROGRAMADORLogin → Mesa · (puede leer la cartelera y los relatos)
VECINA MAYORCartelera / Sesión públicas; sin login

[COMPROBADO] Seis rutas del encargo L1. No se inventan /buscar, /lomo, /programa, /hoy (JWT ONDA), /nodos, /alta, /playlist, /taquilla.

El relato es ruta (/sesion/:code): F-STORY necesita URL compartible y un paso antes del form. [DECISIÓN]
El form es ruta (/pedir/:code): pedir es un paso, no un POST oculto en el feed. [DECISIÓN]
/ok/:code usa el código de sesión (BOB-2604), no un código de petición distinto. L1 compacto. [DECISIÓN]
No hay /buscar: no hay S-CMD. El hallazgo es el feed. [DECISIÓN]

3. Navegación

Dock (S-DOCK · todas las superficies salvo login/ok pueden mostrarlo)

SlotDestinoVisibilidadNotas
Cartelera/TodosVuelve al feed Pliego. No es hero de marca
PedirÚltima sesión ABIERTA o promptTodosAtajo al form; si no hay contexto → cartelera
Mesa/mesaPROGRAMADOR; si guest → /login?next=/mesaOficio JWT

[DECISIÓN] El dock es la navegación primaria. No hay comando (LOMO), no hay rail Estudio/Buscar/Hoy (ONDA), no hay split (RAMAL), no hay kiosk mínimo (TEMPLE).

Desktop ≥960px: dock flotante inferior o anclado; feed full-bleed con overlay.
Mobile ~390px: dock fijo inferior Cartelera · Pedir · Mesa. [DECISIÓN] En 390 el dock no compite con un hamburger.

Cartelera pública (H-FEED Pliego)

ElementoDestinoNotas
Still a sangre≥40 % del recorte 16/10; foto-led
Wordmark BOBINA/Sello brass sobre velvet
Eslogan«La butaca, no la taquilla.»
Tarjeta de sesión/sesion/:code4 noches; título, noche, butacas, estado
Dock Mesa (mute)/login o /mesa si hay tokenOficio, no CTA de marca

[DECISIÓN] La cartelera no tiene tabs de marketing, no tiene «Taquilla / Filmin / Estrenos». El feed basta para hallar.

Chrome de relato y pedir (F-STORY)

SlotDestinoNotas
← Cartelera/Un paso atrás, no stepper de 5
Relato/sesion/:codeNoche + película + butacas + blurb
Pedir butaca/pedir/:codeForm; no wizard 1—2—3
EnviarPOST → /ok/:codeUna acción

Chrome de mesa (/mesa autenticado)

SlotDestinoVisibilidadNotas
Mesa/mesaAuthTitular de oficio
ListaAuthSesiones de la semana
PedidosAuthNombre + código; no columnas
Cartelera/AuthSecundario vía dock
Salirlimpia token → /AuthCabecera de mesa, no cuarto slot del dock

[DECISIÓN] No hay S-SPLIT (RAMAL). No hay kanban (PREGÓN). No hay /mesa/:code: L1 lee lista + pedidos. Could L+1: ficha de pedido.

4. Etiquetas de IA (UI)

ConceptoLabel
HomeCartelera (no «Inicio», no «Hoy» tipo LOMO, no «Galería»)
RelatoSesión (no «lomo», no «programa», no «track»)
FormPedir butaca
SuccessPedida / código
StaffMesa (no «Backoffice», no «Kanban», no «Hoy» JWT ONDA)
AuthProgramadora (no «Área cliente», no «Bibliotecaria»)
CTAPedir butaca (no «Comprar», no «Reservar 2 h», no «Ver en Filmin»)

En docs puede decirse «cartelera feed» para H-FEED y «mesa PROGRAMADOR» para el oficio JWT. En UI pública el titular es Cartelera. En UI autenticada el titular es Mesa. [DECISIÓN]

5. Contenido de cada nodo de IA

RutaQué hayQué no hay
/Still, eslogan, 4 tarjetas, dockPrecios, login de vecino, play Filmin, métricas tabulares
/sesion/:codeCover, título, director, noche, butacas, blurb, CTATicket, follow, player
/pedir/:codeNombre, sesión en solo lectura, disclaimerDNI, email, pago, socio
/ok/:codeCódigo + 4 oposicionesContrato, ticket, «ya está inscrito»
/loginEmail / clave PROGRAMADORSignup de vecino
/mesaLista de 4 + pedidosColumnas Recibido / En curso; split ficha

6. Error / empty / loading (sitio)

Viven en las mismas rutas, no en URLs extra.

EstadoSuperficie
LoadingSkeletons de still + 4 tarjetas / relato / lista de mesa
Empty cartelera«Aún no hay noches.»
Empty mesa«No hay pedidos.»
Error red«La red no responde» + Reintentar
404 sesión«Esa sesión no está» en relato
CompletaCTA disabled · «Completa. Sin butacas.»

7. Profundidad y hallazgo

No hay búsqueda Must: el hallazgo es el feed de 4 noches. Introducir /buscar copiaría LOMO/PIZARRA y rompería la terna. [DECISIÓN]
Marta no filtra la mesa en v1: ve la semana entera + pedidos. Could L+1: filtro por estado ABIERTA/COMPLETA.

8. Códigos y URLs

PiezaForma
SesiónBOB-2601BOB-2604 (BOB versales, guion, 4 dígitos)
Relato/sesion/BOB-2604
Pedir/pedir/BOB-2604
Success/ok/BOB-2604

9. Mapa Paper → rutas

ArtboardRutaComponente
UI-01 Cartelera feed/CarteleraPage
UI-02 Cartelera mobile/ @390CarteleraPage
UI-03 Sesión/sesion/:codeSesionPage
UI-04 Sesión mobile/sesion/:code @390SesionPage
UI-05 Pedir/pedir/:codePedirPage
UI-06 Success/ok/:codeOkPage
UI-07 Login/loginLoginPage
UI-08 Mesa/mesaMesaPage
UI-09 Emptymismas rutasestados
UI-10 Error+Loadingmismas rutasestados
UI-11 Dockchrome globalDockComponent

[COMPROBADO] Mapeo alineado a docs/00-paper-reference.md.

04-user-flows.md

04 — Flujos de usuario — BOBINA

1. Convenciones

TokenSignificado
F-STORYRelato de sesión antes del CTA; la home no es el form
MesaLista PROGRAMADOR, JWT
201Pedido creado (pedida)
409Sesión COMPLETA o sin remaining
401Mesa sin token
404Sesión inexistente

2. F1 — Vecino pide butaca desde el feed (Must)

/  →  GET /api/sesiones
   →  ve Cría cuervos COMPLETA (contexto)
   →  tap El sur  →  /sesion/BOB-2604
   →  GET /api/sesiones/BOB-2604
   →  tap Pedir butaca  →  /pedir/BOB-2604
   →  escribe nombre «Luis Navarro»
   →  POST /api/sesiones/BOB-2604/pedir  { nombre, note? }
   →  201 { code: BOB-2604, title, status, remaining, pedida: true }
   →  /ok/BOB-2604

Entrada: cartelera feed, sin cuenta.
Salida: código visible + copy «pedir butaca ≠ entrada Cinesa».
Errores: red (reintentar), 404 sesión, 409 completa, 0 sesiones (empty).

AC

  • El form no pide email, DNI, pago ni signup.
  • POST no cobra, no crea user, no abre Filmin, no mueve kanban.
  • /ok/BOB-2604 muestra las cuatro oposiciones.
  • El paso /sesion/:code existe: F-STORY no es un POST oculto en el feed. [DECISIÓN]
  • El paso /pedir/:code existe: pedir no es un modal efímero sin URL. [DECISIÓN]

3. F2 — Vecino abre sesión COMPLETA (Must · estado)

/  →  tap Cría cuervos  →  /sesion/BOB-2603
   →  GET /api/sesiones/BOB-2603
   →  remaining 0 · status COMPLETA
   →  CTA Pedir butaca disabled

AC

  • No se permite POST sobre COMPLETA (409 si se fuerza).
  • Copy: «Completa. Sin butacas.» No «agotado tipo Cinesa» ni «comprar otra sesión».
  • Luis puede volver al feed y elegir El sur.

4. F3 — Programadora entra a mesa (Must)

/login  →  POST /api/auth/login
        →  JWT PROGRAMADOR
        →  /mesa
        →  GET /api/mesa

AC

  • Sin token, /mesa redirige a /login?next=/mesa.
  • GET /api/mesa sin Bearer → 401.
  • Lista de la semana: 4 filas + pedidos. No columnas Recibido / En curso.
  • Desktop: lista + pedidos en el panel. 390: apilado sobre el dock.

5. F4 — Estados de sistema

EstadoTriggerUI
Loading carteleraGET sesiones en vueloSkeletons de still + 4 tarjetas
Empty cartelera200 []«Aún no hay noches.»
Error cartelera5xx / redReintentar
Loading sesiónGET :codeSkeleton de relato
404 sesióncódigo inexistente«Esa sesión no está.»
Loading pedirForm listo; submit pending
409 pedirCOMPLETA o remaining 0«No se puede pedir esa butaca.»
Loading mesaGET mesa en vueloSkeletons de fila + pedidos
Empty mesa200 { pedidos: [] }«No hay pedidos.» (las 4 filas pueden existir)
Login 401credenciales«Email o contraseña no valen.»

6. Flujos que no existen

FlujoPor qué
Signup vecinoS2 · Pedir ≠ socio
Comprar entrada CinesaS4 · Pedir butaca ≠ entrada
Ver en Filmin / playCartelera ≠ Filmin
Chat≠ PREGÓN
Alta de nodo≠ RAMAL
Pedir repetición≠ ONDA
Pedir mesa de lomo / comando≠ LOMO
Wizard 1—2—3Pedir es un form corto
Login InmaSlice L1 · docs / a11y
PATCH estado de sesiónMarta lee; no mueve columnas en v1
Catálogo VOD completoH3 · S4
Coger slot de 2 h≠ TEMPLE
Búsqueda ?q=Sin S-CMD

7. Tiempos de demo (modelo)

ActorRecorridoTecho
LuisCartelera → El sur → pedir → pedida< 90 s
Luis (completa)Cartelera → Cría cuervos → vuelve → El sur< 90 s
MartaLogin → mesa → leer BOB-2604< 45 s

No son KPIs medidos. Son techos de diseño para el guión. [HIPÓTESIS]

8. Guión de demo canónico

  1. / — still a sangre + 4 noches. Cría cuervos COMPLETA. El sur ABIERTA. Eslogan. Dock.
  2. Tap Cría cuervos — relato COMPLETA · 0 butacas · CTA disabled.
  3. Tap El sur — relato ABIERTA · 14 butacas · director Erice.
  4. Pedir butaca — /pedir/BOB-2604 · nombre Luis Navarro · note opcional.
  5. Enviar — /ok/BOB-2604. Copy ×4.
  6. /loginmarta@bobina.cine / password123.
  7. /mesa — lista + pedidos; BOB-2604; pedido de Luis si se hizo el POST.
  8. 390: feed + dock; no carousel; targets ≥44px.
  9. API down: error + Reintentar.

9. Contratos de error de API (flujo)

CasoHTTPUI
POST pedir, code inexistente404«Esa sesión no está.»
POST pedir, COMPLETA / remaining 0409«No se puede pedir esa butaca.»
POST pedir, nombre vacío400«Escribe un nombre.»
POST pedir, redoxblood + Reintentar; no navega a ok
GET mesa sin JWT401redirect login
Login malo401copy de login

10. Dock en flujo

DesdeSlot PedirComportamiento
/ sin contextoPedirScroll al primer ABIERTA o mensaje «Elige una noche»
/sesion/BOB-2604 ABIERTAPedir/pedir/BOB-2604
/sesion/BOB-2603 COMPLETAPedirDisabled o mensaje completa
/ok/:codeCarteleraVuelve al feed

[DECISIÓN] El slot Pedir del dock no inventa una quinta sesión; reutiliza contexto de ruta o el primer ABIERTA del feed.

05-data-model.md

05 — Modelo de datos — BOBINA

1. Visión general

Dominio L1 de cartelera de sesiones + relato + pedir autenticable:

EntidadTabla SQLPropósito
UserusersIdentidad de oficio (rol PROGRAMADOR)
SessionsessionsSesión JWT / token persistido
SesiónsesionesNoche programada (código BOB-XXXX, butacas, estado, cover)
PedidopedidosButaca anónima de cuenta sobre una sesión

Base: PostgreSQL (Neon project tiny-feather-31905339) · IDs: serial + texto estable (BOB-2601).
[DECISIÓN] ensureSchema es válido si el contrato de tablas se cumple; el brief de stack no exige Prisma.

Contrato de producto: sesiones + pedidos + JWT PROGRAMADOR.
No ejemplares / programas / repeticiones / nodes / altas / rooms / bookings.

2. Enums (aplicación; persistidos como TEXT + check)

Role

ValorDescripción
PROGRAMADORProgramadora de la mesa; único rol autenticado v1

SesionStatus

ValorDescripción
ABIERTAQuedan butacas (remaining > 0); se puede pedir
COMPLETAremaining = 0; no es «vendida tipo Cinesa»

Pedir butaca solo está permitido en ABIERTA con remaining > 0. COMPLETA responde 409. [DECISIÓN]

Tras un POST exitoso: remaining = remaining - 1; si llega a 0 → status = COMPLETA. [DECISIÓN]

3. Diagrama ER (texto)

users
  id, email, password_hash, name, role(PROGRAMADOR)
  created_at
  1 ──< sessions

sessions
  id, user_id → users
  expires_at, revoked_at
  created_at

sesiones
  id
  code (unique, BOB-XXXX)
  title, director, when_label
  seats, remaining
  status (ABIERTA|COMPLETA)
  cover, blurb
  sort_order
  created_at, updated_at
  1 ──< pedidos

pedidos
  id
  sesion_id → sesiones
  code (denorm BOB-XXXX, opcional)
  name
  note
  created_at

v1: una sola PROGRAMADOR opera sobre el conjunto global.
No hay FK de vecino-usuario: el vecino no se loguea.
pedidos.name es el nombre de sala (oral), no una cuenta.
pedidos.note es texto libre opcional («voy con Inma»).

4. Tablas

users

ColumnaTipoNotas
idBIGSERIAL PK
emailTEXT UNIQUEmarta@bobina.cine
password_hashTEXTbcrypt 12 · seed $2b$12$OEKcNck63neDJ.CrVP0lNOaXp2NG2zd2aMiGmnYY221h4ZAZ58x1m
nameTEXTMarta Ruiz
roleTEXTPROGRAMADOR
created_atTIMESTAMPTZ

sessions

ColumnaTipoNotas
idUUID PKsid del JWT
user_idBIGINT FK
expires_atTIMESTAMPTZ
revoked_atTIMESTAMPTZlogout
created_atTIMESTAMPTZ

sesiones

ColumnaTipoNotas
idBIGSERIAL PK
codeTEXT UNIQUEBOB-2601
titleTEXTEl espíritu de la colmena
directorTEXTVíctor Erice
when_labelTEXTjue 27 ago 20:00 (label humano; no timezone engine en v1)
seatsINTEGERCapacidad total
remainingINTEGERButacas libres
statusTEXTABIERTA | COMPLETA
coverTEXT/assets/sesiones/colmena.jpg
blurbTEXTRelato corto. Sesión ≠ estreno.
sort_orderINTEGER1 = primera del feed
created_at / updated_atTIMESTAMPTZ

pedidos

ColumnaTipoNotas
idBIGSERIAL PK
sesion_idBIGINT FK
codeTEXTDenorm BOB-2604 para mesa sin join extra
nameTEXTNombre de sala (Luis Navarro)
noteTEXT NULLNota opcional
created_atTIMESTAMPTZ

Sin email, sin teléfono, sin DNI, sin pago. Pedir butaca ≠ entrada Cinesa. [DECISIÓN]

Índices: sesiones(code), sesiones(status), sesiones(sort_order), users(email), pedidos(sesion_id), pedidos(created_at DESC).

5. Seed

PROGRAMADOR

marta@bobina.cine / password123 · Marta Ruiz · PROGRAMADOR
Hash bcrypt fijo: $2b$12$OEKcNck63neDJ.CrVP0lNOaXp2NG2zd2aMiGmnYY221h4ZAZ58x1m

Sesiones

codetitledirectorwhen_labelseatsremainingstatuscover
BOB-2601El espíritu de la colmenaVíctor Ericejue 27 ago 20:001212ABIERTA/assets/sesiones/colmena.jpg
BOB-2602Los golfosCarlos Sauravie 28 ago 21:0088ABIERTA/assets/sesiones/golfos.jpg
BOB-2603Cría cuervosCarlos Saurasáb 29 ago 19:30120COMPLETA/assets/sesiones/cuervos.jpg
BOB-2604El surVíctor Ericedom 30 ago 18:001414ABIERTA/assets/sesiones/sur.jpg
codeblurb (catálogo)sort
BOB-2601Erice en la sala del barrio. Quedan butacas. No es Cinesa.1
BOB-2602Saura a las 21:00. Calle y noche. Pedir butaca ≠ ticket.2
BOB-2603Completa. Sin butacas. La bobina ya tiene dueños de asiento.3
BOB-2604El sur al atardecer. Dom 18:00. Sesión ≠ estreno.4

[SUPUESTO de cartelera] Títulos, blurbs y butacas son atrezzo. No es una programación oficial.
[DECISIÓN] BOB-2603 usa seats=12 demo con remaining=0 para mostrar COMPLETA; el encargo lista 0 butacas = remaining.

Pedidos

Seed opcional vacío o una fila demo sobre BOB-2603 (ya COMPLETA) no es necesaria.
El POST de smoke crea la de Luis sobre BOB-2604.
Marta puede ver 0 pedidos al entrar en frío y ≥1 tras el guión.

El seed idempotente restaura los 4 estados de catálogo (3 ABIERTA, 1 COMPLETA) y los remaining de catálogo para que el demo sea repetible. [DECISIÓN]

6. JSON (camelCase)

API: sortOrder, createdAt, pedidoCount, whenLabel, cover, status, title, director, code, blurb, seats, remaining, name, note.
SQL: sort_order, created_at, when_label, pedido_count derivado.

GET /api/sesiones (item)

{
  "code": "BOB-2604",
  "title": "El sur",
  "director": "Víctor Erice",
  "whenLabel": "dom 30 ago 18:00",
  "seats": 14,
  "remaining": 14,
  "status": "ABIERTA",
  "cover": "/assets/sesiones/sur.jpg",
  "blurb": "El sur al atardecer. Dom 18:00. Sesión ≠ estreno.",
  "sortOrder": 4
}

Lista pública: no incluye name de pedidos (evita enumerar vecinos). [DECISIÓN]

GET /api/sesiones/:code

Mismo shape; puede incluir campos de relato ya presentes (blurb, director).

POST /api/sesiones/:code/pedir

Request:

{ "name": "Luis Navarro", "note": "Voy con Inma" }

note opcional. name obligatorio, trim, min 2 caracteres. [DECISIÓN]

Response 201:

{
  "code": "BOB-2604",
  "title": "El sur",
  "status": "ABIERTA",
  "remaining": 13,
  "pedida": true
}

GET /api/mesa (JWT)

{
  "sesiones": [ /* 4 items + pedidoCount */ ],
  "pedidos": [
    {
      "id": 1,
      "code": "BOB-2604",
      "name": "Luis Navarro",
      "note": "Voy con Inma",
      "createdAt": "2026-08-26T16:12:00.000Z"
    }
  ]
}

7. Reglas de integridad

ReglaDetalle
Unicidad de códigosesiones.code UNIQUE
Pedir solo ABIERTASi status ≠ ABIERTA o remaining ≤ 0 → 409
Decremento atómicoUPDATE remaining = remaining - 1 WHERE remaining > 0; si 0 filas → 409
Transición a COMPLETATras update, si remaining = 0 → status = COMPLETA
Sin user en pedidoNo FK a users desde pedidos
Mesa privadaGET /api/mesa exige JWT role PROGRAMADOR
Feed públicoGET /api/sesiones sin auth

8. Fuera del modelo v1

ConceptoPor qué fuera
Precio / pago / QRPedir ≠ Cinesa
Email del vecinoMinimización; S2
confirmada_at / north-star SQLAnalytics modelo; doc 12
Tabla ejemplaresLeftover LOMO
Tabla programasLeftover ONDA
Multi-tenant asociaciónL1 compacto

9. Naming vs leftover

Prohibido (leftover)Contrato BOBINA
ejemplaressesiones
BIBLIOPROGRAMADOR
lomo-apibobina-api
LM-XXXXBOB-XXXX
DISPONIBLE / EN_SALA / PEDIDOABIERTA / COMPLETA
sala (1–3)when_label + seats/remaining

06-tech-stack.md

06 — Stack técnico — BOBINA

1. Resumen

CapaElecciónNotas
FrontendAngular (standalone) + TailwindPuerto 4200
BackendNestJSPuerto 3026 · prefijo /api
DBNeon PostgreSQLProject tiny-feather-31905339
AuthJWT BearerRol PROGRAMADOR
PackagepnpmApps independientes (pnpm --filter)
DiseñoPaperFile 01M0YE7DABVQNCPYK4JQPCSEEQ
Repo/Users/cristian/orca/bobina-appGH Criscode2022/bobina-app

[COMPROBADO] Angular + NestJS + Neon + Tailwind, puerto API 3026, Neon id y path de app salen del encargo.

2. Por qué este stack

DecisiónRazónAlternativa descartada
Angular standaloneCoherencia serie ALS-2 dailyNext/React (rompería espejo de cases)
NestJSMismo contrato API que LOMO/ONDAExpress suelto sin módulos
NeonPostgres managed; project dedicadoSQLite local (no portfolio cloud)
TailwindTokens candlelit rápidosCSS modules sin design tokens
JWTMesa cerrada; feed abiertoSession cookie-only sin Bearer documentado
pnpm filterMonorepo ligero sin npm workspacesTurborepo pesado para L1

3. Puertos y health

ServicioPuertoHealth
API3026GET /api/health{ ok: true, service: "bobina-api" }
Web4200Angular dev server

Leftover lomo-api / puerto 3025 / onda-api no son el producto. [DECISIÓN]

4. Estructura de repo (contrato)

bobina-app/
  apps/
    api/          NestJS · PORT=3026
    web/          Angular · 4200
  package.json    pnpm workspaces o filter

Proxy web → API en dev (/apihttp://localhost:3026). [DECISIÓN]

5. Variables de entorno (API)

VariableUso
DATABASE_URLNeon connection string (tiny-feather-31905339)
JWT_SECRETFirma HS256
PORT3026
NODE_ENVdevelopment / production

No commitear secretos. .env local; ejemplo en .env.example sin credenciales reales. [DECISIÓN]

6. Auth

PiezaDetalle
LoginPOST /api/auth/login { email, password }
Hashbcrypt 12 · seed fijo del encargo
TokenJWT · claims sub, email, role: PROGRAMADOR
GuardBearer en GET /api/mesa
Públicohealth, sesiones, sesiones/:code, POST pedir, login
Storage weblocalStorage o memory + interceptor; logout limpia

[COMPROBADO] Credenciales demo: marta@bobina.cine / password123.

7. Endpoints (contrato)

MétodoRutaAuthRespuesta clave
GET/api/healthNobobina-api
GET/api/sesionesNoArray 4
GET/api/sesiones/:codeNoRelato
POST/api/sesiones/:code/pedirNo201 / 409 / 404 / 400
POST/api/auth/loginNo{ accessToken }
GET/api/mesaJWTsesiones + pedidos

CORS: origen http://localhost:4200 en dev. [DECISIÓN]

8. Frontend — rutas y componentes

RutaComponenteGuard
/CarteleraPage
/sesion/:codeSesionPage
/pedir/:codePedirPage
/ok/:codeOkPage
/loginLoginPage
/mesaMesaPageauthGuard PROGRAMADOR

Chrome: DockComponent (S-DOCK). Tokens Tailwind: ground, cream, card, brass, mute, oxblood.

9. Assets

Origen caseDestino app
2026-08-26-bobina/assets/hero.jpgCover / reference
assets/sesiones/*.jpgapps/web/public/assets/sesiones/ o equivalente

Covers en DB como paths /assets/sesiones/colmena.jpg etc. [DECISIÓN]

10. Calidad y toolchains

HerramientaUso v1
TypeScriptStrict en api y web
ESLint / PrettierSerie daily
Vitest / JestSmoke API opcional L1
PlaywrightCould; smoke manual en doc 13

11. Anti-stack (no introducir)

TecnologíaPor qué no
Prisma obligatorioBrief no lo exige; ensureSchema + pg válido
Stripe / pagoPedir ≠ Cinesa
Firebase AuthJWT propio PROGRAMADOR
GraphQLREST L1
Socket.io / chat≠ PREGÓN
Player video≠ Filmin
OPAC / Absys libs≠ LOMO

12. Criterios de aceptación técnicos

  1. GET /api/healthservice: "bobina-api".
  2. Seed idempotente: 1 PROGRAMADOR + 4 sesiones.
  3. POST pedir decrementa remaining y puede pasar a COMPLETA.
  4. GET mesa sin token → 401.
  5. Web en 4200 consume API 3026 sin mixed-content local.
  6. 0 referencias de producto a ejemplares, BIBLIO, lomo-api en runtime.

[COMPROBADO] Contrato alineado a docs 01, 05 y README.

07-creative-direction.md

07 — Dirección creativa — BOBINA

1. Concepto

BOBINA es una sala a oscuras bajo terciopelo: se entra a un still a sangre con cuatro noches encima y se sale habiendo pedido una butaca, no una landing de «tu cine». El ground es velvet. El latón puntúa, poco. El oxblood marca completa / error, poco.

Mood elegido: candlelit.
Primer instinto descartado: nocturnal / neón de cine (multiplex). Un cineclub de barrio se enciende con apliques de latón, no con LED de Cinesa.

[COMPROBADO] Mood, ground y paleta salen de docs/00-day-brief.md.

2. Territorio visual

EjeNo
SuperficieVelvet #1A1210, cream #F4EDE4, card #241C18, brass #C4A574Caliza LOMO, cinta ONDA, hielo RAMAL, niebla PREGÓN
TipoCormorant Garamond + ManropeSource Serif+Outfit (LOMO), DM Serif+IBM Plex, Newsreader+Figtree
FotoStill de sala a oscuras, butaca, haz de proyector, barrioLED multiplex, marquee Times Square, stock Filmin
GridPliego: still ≥40 % 16/10 + feed overlay de 4 nochesHero 2-col + 3 cards (AP-12) · mesa de datos (LOMO) · galería 16/10 radio (ONDA)
AcentoBrass en CTA/foco/dock activo; oxblood en COMPLETA/errorCobre mineral LOMO, cinta amarilla ONDA
ChromeDock Cartelera · Pedir · MesaComando archivo, rail radio, split, kiosk

3. Paleta

TokenHexRol
Ground / G-VELVET#1A1210Terciopelo de butaca. Fondo de página.
Cream#F4EDE4Texto primario, ficha legible sobre velvet.
Card#241C18Asiento / tarjeta de sesión. Superficie elevada.
Brass#C4A574Latón: CTA Pedir, foco, wordmark. Poco.
Mute#8A7A6EMeta, labels, noche secundaria, idle dock
Oxblood#9A3B2FSello COMPLETA y error. Poco. No pinta el header.

Jerarquía de color: el velvet carga; el brass puntúa; el oxblood marca completa. Si el brass pinta fondos enteros, deja de ser latón y se vuelve «brand dorado». El oxblood no decora la cabecera: solo puntual (COMPLETA, error). El texto sobre velvet es cream; nunca mute como párrafo largo. Cream sobre velvet debe pasar contraste WCAG 2.2 AA. [DECISIÓN]

Candidatos de mood descartados: nocturnal/neón (primer instinto multiplex), chapel, rusted, subterranean.

4. Tipografía

UsoFamiliaTamaños de referencia
WordmarkCormorant Garamond 60024–28 desktop · 22 mobile
Titular de cartelera / sesiónCormorant Garamond 60032–44
Código BOB-XXXXCormorant Garamond 60028–36
Título de películaCormorant Garamond 60022–28
Cuerpo / disclaimersManrope 40016–17 / 26–28 lh
UI, dock, form, listaManrope 400/500/60014 / 16
Meta (noche, status, director)Manrope 50012–13, tracking 0.08em, cream o mute

Prohibido: Cormorant por debajo de 18px (se rompe). Manrope en el wordmark de cartelera (se vuelve SaaS). Brass como color de texto de párrafo largo (contraste).

Fuentes vetadas de la serie reciente cuando el brief fija otras: Source Serif 4 / Outfit (LOMO), DM Serif Display / IBM Plex Sans, Newsreader / Figtree, Fraunces / Atkinson, etc. Cormorant + Manrope entran: el brief los fija. [COMPROBADO]

5. Fotografía

AssetDebeNo debe
hero.jpgStill de sala a oscuras: velvet, haz, butaca, barrioMarquee neón, multiplex, stock Filmin
colmena.jpgAtmósfera de Colmena / Erice; grano, interiorPóster comercial con rating
golfos.jpgCalle / noche Saura; cineclubCartel de estreno Cinesa
cuervos.jpgInterior / infancia / sombra; COMPLETA se lee en UIPlay button overlay tipo VOD
sur.jpgLuz de atardecer / umbral; ABIERTATrailer thumbnail YouTube

Alt: película + noche, no «imagen1». Ver doc 09.

[COMPROBADO] Los cuatro covers existen en assets/sesiones/.

6. Registro R-IN

Inmersión de sala a oscuras (velvet) + dock flotante + feed sobre foto a sangre. No es un dashboard de seguros. No es un kiosk de horas. No es una mesa de datos de archivo. No es neón de multiplex.

La innovación está en H-FEED Pliego + S-DOCK + F-STORY, no en un look «cine LED». [DECISIÓN]

7. Anti-moods

MoodPor qué no
Neón / nocturnal multiplexPrimer instinto; es Cinesa
Mineral / calizaFue LOMO
Signage / cinta amarillaFue ONDA
Ice institucionalFue RAMAL
Vehicle dashboardFue TEMPLE
Highlighter fogFue PREGÓN
Chapel amatistaFue MATIZ

8. Densidad (AP-21)

En el recorte Pliego: eslogan + still dominante + 4 tarjetas con título, noche, butacas y estado visibles sin hover. Headline huérfano + foto = card hueca. [COMPROBADO] CRON §5.8 / D-P1-09 foto-led.

Still ≥40 % del recorte 16/10. Feed overlay no tapa el oficio de la foto: legible, no sticker. [DECISIÓN]

9. Motion

GestoTratamiento
Entrada feedFade corto 120–160ms; still estático (no Ken Burns agresivo)
Hover tarjeta desktopRing brass 2px; sin lift excesivo
Dock activoBrass en label/icono; idle mute
Reduced motion0ms; still sin parallax

10. Voice visual ↔ copy

El mood candlelit refuerza el microcopy: butaca de sala, no taquilla. Si la UI parece multiplex (neón, QR, precio), el copy irrenunciable pierde fuerza. [DECISIÓN]

08-design-system.md

08 — Sistema de diseño — BOBINA

1. Tokens

TokenValorUso
--ground#1A1210Fondo de página (velvet)
--cream#F4EDE4Texto primario, títulos
--card#241C18Tarjeta de sesión, form, mesa
--brass#C4A574CTA, foco, dock activo
--mute#8A7A6EMeta, idle
--oxblood#9A3B2FCOMPLETA, error
--font-displayCormorant GaramondTitulares
--font-sansManropeUI
--target44×44 minToques

Tailwind: bg-ground, text-cream, bg-card, bg-brass, text-mute, text-oxblood, font-display.
La tarjeta vive sobre --card; el ground es velvet alrededor. [DECISIÓN]

2. Contraste (obligatorio)

ParUsoNota
Cream #F4EDE4 sobre Velvet #1A1210Cuerpo y títulosDebe pasar WCAG 2.2 AA
Cream sobre Card #241C18Texto en tarjetaVerificar AA
Brass sobre VelvetSolo UI chrome / iconos, no párrafos largosNo sustituye cream
Mute sobre VelvetMeta corta; no cuerpoEvitar párrafos mute
Oxblood sobre VelvetSello COMPLETA + texto de error cortoCon cream adyacente si hace falta

[DECISIÓN] Brass nunca como color de párrafo. Mute nunca como único color de disclaimer largo.

3. Escala de tipo

RolSize / leading
Display carteleraclamp(2.2rem, 5vw, 3.6rem) / 0.95
H1 sesión / mesa2.5rem / 1
H2 película28px / 32px
Cuerpo16–17 / 26
Meta12–13 / 16, tracking 0.08em
Dock12–14 / 16, Manrope 500

4. Componentes

Tarjeta de sesión (feed)

Cover recorte + título Cormorant · director · when_label · remaining/seats · status. Toda la tarjeta es el hit. Destino /sesion/:code. Orden por sort_order.

Still Pliego (UI-01)

Imagen a sangre ≥40 % del frame 16/10; gradient velvet→transparente para legibilidad del feed; wordmark + eslogan.

Relato de sesión

Cover, título display, dl director / noche / butacas / estado, blurb, bloque de copy irrenunciable, CTA Pedir butaca (cream sobre brass o brass outline según contraste).

Form pedir

Nombre, note opcional, sesión en solo lectura (código, título, noche), disclaimer, submit brass.

Success

Código Cormorant enorme + bloque card con título y noche + 4 oposiciones en cream/mute.

Fila de mesa PROGRAMADOR

Código · status · título · when_label · remaining · pedidoCount. Pedidos debajo: name · code · note · hora. Sin acciones PATCH en v1.

Login

Wordmark + dos inputs + CTA brass. Ayuda mute con demo.

Dock (S-DOCK)

Tres slots: Cartelera · Pedir · Mesa. Activo: brass. Idle: mute. Fondo card/velvet con blur ligero opcional. Targets ≥44px.

Skeleton

animate-pulse bg-card. aria-busy.

Error

Titular display + cuerpo cream/mute + Reintentar brass.

Sello COMPLETA / ABIERTA

Texto «Completa» / «Abierta» + oxblood o brass/mute. Nunca solo el color. Poco: un sello por vista, no un header oxblood.

5. Layouts

SuperficieGrid
Cartelera 1440Still full-bleed; feed overlay 1 col o 2×2 de tarjetas; dock
Cartelera 390Still + stack de 4 tarjetas; dock fijo inferior
Sesión / Pedir / Ok / loginColumna max-w-lg (ok/login/pedir) · max-w-2xl (relato)
Mesa PROGRAMADORLista + pedidos; stacked < lg

Max page 1440px. Padding 20 / 40 / 48.

6. Estados de control

EstadoTratamiento
DefaultCard + cream
HoverRing brass 2px
Focus visibleOutline brass 2px offset 2
Active / pressedBrass fill breve
DisabledOpacity 0.45 · no hit · aria-disabled
Pendingdisabled + aria-busy
ErrorBorde oxblood + mensaje

7. Iconografía

Dock: pictogramas simples (cartelera / butaca / mesa). Stroke 1.5–2px. No icon packs «ticket multiplex». [DECISIÓN]

8. Elevación y bordes

SuperficieTratamiento
Card sobre velvetSin sombra dura; borde 1px brass/10 o mute/20
DockElevación suave + blur; no material neón
Modal (si hubiera)No en v1 Must

9. Mapa a Paper UI

UIComponentes clave
UI-00Tokens
UI-01 / 02Still + tarjetas + dock
UI-03 / 04Relato
UI-05Form
UI-06Success
UI-07Login
UI-08Mesa
UI-09Empty
UI-10Error + Loading
UI-11Dock

[COMPROBADO] Inventario en 00-paper-reference.md.

09-content-guide.md

09 — Guía de contenido — BOBINA

1. Voz

BOBINA habla como sala de cineclub, no como taquilla ni como app de streaming.

EjeNo
TonoCálido, breve, de barrioCorporativo multiplex, hype de estreno
Persona«Pedimos butaca» / tuteo de sala«Adquiere tu entrada»
RitmoFrases cortas. Una idea por línea en disclaimersPárrafos legales de Filmin
HumorSeco, pocoMemes, spoilers

[DECISIÓN] Tuteo en UI. Marta en mesa puede verse en usted solo en docs, no en labels.

2. Microcopy irrenunciable

Presente en cartelera (pie o banner), relato, pedir, success y pie de mesa:

OposiciónCopy canónico
Butaca vs CinesaPedir butaca ≠ entrada Cinesa.
Sesión vs estrenoSesión ≠ estreno.
Cartelera vs FilminCartelera ≠ Filmin.
Barrio vs centroBOBINA no es los cines del centro.

No se parafrasean hasta diluirlas. Pueden acortarse en UI estrecha manteniendo ≠. [DECISIÓN]

3. Glosario UI

ConceptoLabel canónicoEvitar
HomeCarteleraInicio, Hoy, Galería, Catálogo
ItemSesión / NocheFunción, pase, screening, lomo
CTAPedir butacaComprar, Reservar entrada, Ver ahora
SuccessPedidaConfirmación de compra, Ticket listo
StaffMesaBackoffice, Admin, Kanban
EstadoAbierta / CompletaDisponible / Agotado (retail), En sala (LOMO)
Persona authProgramadoraBibliotecaria, Conductora, Admin

4. Pantalla a pantalla

Cartelera /

SlotCopy
WordmarkBOBINA
EsloganLa butaca, no la taquilla.
EmptyAún no hay noches.
ErrorLa red no responde. · Reintentar

Sesión /sesion/:code

SlotCopy
CTA ABIERTAPedir butaca
CTA COMPLETACompleta. Sin butacas.
Meta{director} · {when_label} · {remaining} butacas
AvisoPedir butaca ≠ entrada Cinesa.

Pedir /pedir/:code

SlotCopy
TítuloPedir butaca
Label nombreTu nombre
Label noteNota (opcional)
Placeholder noteEj. Voy con Inma
SubmitPedir butaca
DisclaimerNo es una entrada Cinesa. No hay pago. Sesión ≠ estreno.
Error nombreEscribe un nombre.
Error 409No se puede pedir esa butaca.

Success /ok/:code

SlotCopy
TitularPedida.
Código{code}
CuerpoButaca apuntada para {title} · {when_label}.
OposicionesLas cuatro líneas irrenunciables
VolverVolver a la cartelera

Login /login

SlotCopy
TítuloMesa
AyudaSolo programadora.
Demomarta@bobina.cine
ErrorEmail o contraseña no valen.

Mesa /mesa

SlotCopy
TítuloMesa
Empty pedidosNo hay pedidos.
SalirSalir
PiePedir butaca ≠ entrada Cinesa.

5. Alt text de imágenes

AssetAlt (modelo)
heroSala de cineclub a oscuras, butacas de terciopelo, luz cálida
colmenaStill de sesión El espíritu de la colmena
golfosStill de sesión Los golfos
cuervosStill de sesión Cría cuervos
surStill de sesión El sur

Evitar «imagen1», «poster.jpg», spoilers largos. [DECISIÓN]

6. Títulos seed (atrezzo)

Los títulos Erice/Saura son catálogo demo. En UI no se afirma «programación oficial Filmoteca». Blurbs pueden recordar sesión ≠ estreno. [SUPUESTO de cartelera]

7. Tono de error

CasoCopy
RedLa red no responde.
404Esa sesión no está.
409No se puede pedir esa butaca.
401 mesaEntra como programadora.

Sin culpa al usuario. Sin jerga HTTP en UI.

8. Anti-copy (vetado)

VetadoPor qué
Comprar entrada / ticket / QRCinesa
Ver ahora / Play / Mi listaFilmin
Estreno / preestreno / taquillaCircuito
Reservar 2 h / sala de ensayoTEMPLE
Pedir mesa / lomo / signaturaLOMO
Pedir repetición / antenaONDA
Recibido / En curso / CerradoPREGÓN kanban
«El 80% de vecinos…»Estadística inventada

9. Criterios de aceptación de contenido

  1. Las cuatro oposiciones aparecen al menos en success y en una superficie de cartelera o pedir.
  2. Ningún CTA dice Comprar / Play / Entrada.
  3. COMPLETA se etiqueta «Completa», no «Agotado» retail.
  4. Códigos se muestran como BOB-XXXX en versales.
  5. Docs y UI no inventan KPIs numéricos de Vallecas como hecho.

10-accessibility.md

10 — Accesibilidad — BOBINA

1. Objetivo

Cumplir WCAG 2.2 AA en el vertical slice L1. Ground oscuro (velvet): el par cream sobre velvet es el contrato de legibilidad. Inma Peña (68) es persona de diseño que fuerza contraste, tamaño y targets; no tiene login. [COMPROBADO] requisito del encargo · [DECISIÓN] persona Inma en docs.

2. Contraste

ParRatio objetivoUso
#F4EDE4 sobre #1A1210≥ 4.5:1 (texto) / ≥ 3:1 (UI grande)Cuerpo, títulos
#F4EDE4 sobre #241C18≥ 4.5:1Texto en card
#C4A574 sobre #1A1210≥ 3:1 para UI no textoFoco, iconos; no párrafos
#8A7A6E sobre #1A1210Verificar; limitar a meta cortaLabels
#9A3B2F + creamTexto de error legibleErrores / COMPLETA

[DECISIÓN] Si mute falla AA en párrafo, se asciende a cream. Brass no escribe disclaimers.

Verificación: contraste en tokens al build de UI; no se afirman ratios inventados sin medir en implementación. [HIPÓTESIS operativa] cream/velvet pasa; se valida en QA (doc 13).

3. Tipografía y lectura

ReglaAplicación
Cuerpo ≥ 16pxManrope 16–17
Display no < 18pxCormorant solo en titulares
Line-height ≥ 1.5 en cuerpo26–28 lh
Zoom 200%Layout no rompe dock ni form
Sin justificado forzadoAlineación start

4. Targets y pointer

ElementoMínimo
Dock slots44×44 CSS px
CTA Pedir butaca≥ 44 px alto
Tarjeta de sesiónHit area completa ≥ 44 alto
Inputs≥ 44 alto

Spacing entre slots del dock ≥ 8px. [DECISIÓN]

5. Teclado y foco

SuperficieComportamiento
CarteleraTab por tarjetas → dock
RelatoTab a CTA / atrás
FormNombre → note → submit
LoginEmail → password → entrar
MesaLista legible; salir alcanzable
Focus visibleOutline brass 2px offset 2
Skip link«Saltar al feed» en / Could; Must si hay still decorativo largo

Sin keyboard traps. Esc no es obligatorio en v1 (sin modales Must).

6. Semántica y nombres

UIRol / nombre
Docknavigation · aria-label «Dock BOBINA»
Slot activoaria-current="page"
Tarjetaslink o article + enlace «{title}»
StatusTexto visible «Abierta» / «Completa» + no solo color
Formlabel asociado; errores con aria-live="polite"
Loadingaria-busy="true" en región
Success códigoTexto real, no solo imagen

7. Imágenes y still

CasoTratamiento
Still Pliegoalt descriptivo corto o alt="" si puro decorativo y el feed encima lleva el oficio
Covers sesiónAlt «Still de sesión {title}»
Iconos dockaria-hidden si hay label texto visible

[DECISIÓN] Preferir still con alt útil en cover UX; en producto, si el overlay ya nombra BOBINA y las noches, evitar alt redundante largo.

8. Motion

PreferenciaComportamiento
prefers-reduced-motion: reduceTransiciones 0ms; sin parallax del still
Default120–160ms ease-out

9. Estados y color

COMPLETA / ABIERTA / error nunca se comunican solo con color: texto + sello. Oxblood refuerza, no sustituye. [DECISIÓN]

10. Auth y a11y

  • Login solo PROGRAMADOR; Inma no necesita cuenta para leer cartelera.
  • Mensajes de error de login claros, sin enumerar si el email existe (seguridad + claridad).
  • /mesa redirige a login con foco en email.

11. Mobile 390

  • Dock fijo no tapa el CTA final: padding-bottom ≥ altura dock.
  • Formularios: autocomplete name on; password current-password.
  • Viewport meta; sin zoom bloqueado. [DECISIÓN]

12. Criterios de aceptación a11y

  1. Cream sobre velvet usado en cuerpo; mute limitado a meta.
  2. Targets dock y CTA ≥ 44×44.
  3. Focus visible brass en todos los interactivos.
  4. Status con texto, no solo color.
  5. Reduced motion respetado.
  6. Form con labels y errores anunciables.
  7. Ningún toast único sin pantalla como único success (hay /ok/:code).

13. Fuera de v1 (Could)

  • Modo tipográfico «letra grande» persistente para Inma.
  • Transcripciones / audiodescripción de películas (fuera de producto L1).
  • ATAG de CMS (no hay CMS).

11-privacy-security.md

11 — Privacidad y seguridad — BOBINA

1. Principios

PrincipioAplicación v1
MinimizaciónPedido = nombre + note opcional; sin email, teléfono, DNI
Separación público / oficioFeed y POST pedir públicos; mesa JWT
Sin cuenta de vecinoLuis e Inma no se registran
Transparencia de copySuccess dice que no es compra Cinesa
Secretos fuera del repoDATABASE_URL, JWT_SECRET en env

[DECISIÓN] No se inventa un aviso legal largo de Filmoteca; hay disclaimer de producto y minimización real.

2. Datos tratados

DatoDóndeBase operativa (modelo)Retención v1
Nombre de pedidopedidos.namePrestación del cineclub (apuntar butaca)Mientras el seed/demo viva; sin política de mercado afirmada
Notepedidos.noteOpcional; texto libre del vecinoIgual
Email PROGRAMADORusers.emailCuenta de oficioCuenta demo
Password hashusers.password_hashAuthbcrypt 12
JWT sidsessionsSesión de mesaExpiración + revoke

No se tratan: pago, tarjeta, geolocalización, ID de dispositivo publicitario, mensajes de chat.

[SUPUESTO] El cineclub demo opera en España; el slice no implementa un RCPD completo de asociación real.

3. Superficies públicas vs privadas

SuperficiePúblicoPrivado
GET /api/sesionesSí · sin nombres de vecinos
GET /api/sesiones/:code
POST pedirSí · crea pedido
GET /api/mesaNo · 401Sí · pedidos con name
Feed UISin listar quién pidió
Mesa UILista pedidos

[DECISIÓN] Enumerar vecinos en el feed rompería privacidad de sala; solo Marta ve nombres.

4. AuthN / AuthZ

ControlDetalle
Passwordbcrypt cost 12 · hash seed canónico del encargo
JWTHS256 · secret env · role claim
Guard mesarole === PROGRAMADOR
Login rateCould L+1; v1 demo sin brute-force engine
LogoutRevoke session + clear client token
HTTPSObligatorio en deploy; localhost HTTP en dev

Credenciales demo en docs: marta@bobina.cine / password123. No reutilizar en producción real. [COMPROBADO] demo · [DECISIÓN] rotar fuera del case.

5. Amenazas y mitigaciones L1

AmenazaMitigación
POST pedir spamCapacidad remaining; Could rate-limit
Enumeración de pedidosNo en API pública
JWT robadoExpiración corta + logout; HTTPS en prod
IDOR mesaGuard JWT; sin IDs de pedido públicos
XSSAngular escaping; no innerHTML de note sin sanitize
SQLiParámetros prepared / query builder
Leftover ADMINUn solo rol PROGRAMADOR

6. Contenido de note

note es texto libre. No se ejecuta. Se muestra a Marta en mesa. Longitud max sugerida 280 caracteres. [DECISIÓN]
No se pide dirección, salud ni datos de terceros sensibles en el form.

7. Cookies y tracking

v1 no incluye analytics de terceros ni banners de cookies de ads. North star es modelo (doc 12). [DECISIÓN]
Token JWT puede vivir en localStorage (XSS risk aceptado en demo) o memory; documentar en handoff.

8. Logs

Qué síQué no
Errores de API sin PIIPasswords, JWT completos
code de sesión en logs de pedidoNombre completo en logs públicos

9. Criterios de aceptación

  1. GET mesa sin Bearer → 401.
  2. GET sesiones no incluye name de pedidos.
  3. POST pedir no exige auth ni pago.
  4. Password solo como hash bcrypt.
  5. .env no versionado con secretos reales.
  6. Copy de success no implica contrato de compra.

10. Fuera de v1

DPO, ROPA formal, exportaciones ARCO automatizadas, SSO, 2FA, WAF. Roadmap L4 si el cineclub deja de ser demo.

12-analytics.md

12 — Analytics y métricas — BOBINA

1. Norte

TipoMétricaDefinición
North Star% de noches ABIERTA con ≥1 pedido antes de las 18:00Oficio de sala: la noche se llena (o se apunta) antes de la tarde

[COMPROBADO] North star sale del day brief / encargo.
[DECISIÓN] En v1 es modelo: no hay instrumentación obligatoria ni dashboard. No se afirman porcentajes medidos inventados.

2. Por qué esta north star

Alternativa descartadaPor qué no
Pageviews de /Vanidad; no mide butaca
Tiempo en Filmin-likeNo hay VOD
Ingresos de taquillaPedir ≠ Cinesa; no hay pago
% reservas antes de las 11:00Eso es LOMO (archivo mañana)

18:00 es umbral de tarde de barrio antes de la noche de proyección. [SUPUESTO] operativo de diseño, no dato de campo.

3. Métricas de soporte (modelo)

MétricaDefiniciónHipótesis
Activación vecino1.er POST /api/sesiones/:code/pedir exitoso por visitanteH1
Tasa feed → relato//sesion/:codeH1
Tasa relato → pedir/sesion → POSTH2 copy no frena
Rechazo COMPLETAVisitas a BOB-2603 sin POSTEstado claro
Integridad auth401 en mesa sin tokenSeguridad
Salud5xx rate APIOps

4. Eventos (contrato si se instrumenta L+1)

EventoPropsPII
cartelera_viewNo
sesion_viewcode, statusNo
pedir_submitcodeNo nombre
pedir_successcodeNo
pedir_conflictcode, http:409No
login_successroleNo
mesa_viewNo

[DECISIÓN] Nunca enviar name ni note a analytics.

5. Cálculo north star (modelo SQL)

noches_abiertas = sesiones con status ABIERTA en la ventana
noches_con_pedido_pre_18 =
  noches_abiertas donde existe pedido con created_at::time < 18:00
                         (o created_at < día@18:00 local)
ratio = noches_con_pedido_pre_18 / noches_abiertas

Timezone: Europe/Madrid. [DECISIÓN]
v1 puede no persistir confirmada_at; se usa pedidos.created_at. [DECISIÓN]

6. Integridad de expectativa (cualitativa)

Señales a vigilar en demo / soporte (no KPIs inventados):

  • «¿Compro la entrada?»
  • «¿Dónde está el play?»
  • «¿Es el estreno?»
  • «¿Es el cine del centro?»

Mitigación: microcopy irrenunciable (doc 09). [HIPÓTESIS H2]

7. Qué no medir en v1

VetadoPor qué
Heatmaps de terceros sin decisiónPrivacidad
Funnel de pagoNo hay pago
DAU de FilminNo hay VOD
Estadísticas de Vallecas inventadasÉtica de verdad

8. Criterios de aceptación

  1. Docs y UI no muestran un % inventado como hecho.
  2. North star documentada y alineada al brief.
  3. Si hay eventos L+1, sin PII de pedidos.
  4. Health y 401 mesa son checks de integridad, no vanidad.

9. Relación con seed

Seed tiene 3 ABIERTA + 1 COMPLETA. Un guión con POST sobre BOB-2604 antes de las 18:00 es el ejemplo narrativo del north star; no es un dato de mercado. [SUPUESTO de demo]

13-qa-test-plan.md

13 — Plan de QA — BOBINA

1. Alcance

Smoke y regresión del vertical slice L1: feed, relato, pedir, success, login, mesa, empty/error/loading, mobile 390, contraste cream/velvet.
No incluye campo real de Vallecas ni load test de multiplex.

2. Entornos

EntornoURLNotas
API localhttp://localhost:3026Neon tiny-feather-31905339
Web localhttp://localhost:4200Proxy /api
Credencialesmarta@bobina.cine / password123Solo demo

3. Smoke crítico (Must pasar)

IDCasoPasosEsperado
S01HealthGET /api/healthok · service: "bobina-api"
S02FeedGET /api/sesiones · abrir /4 sesiones · Pliego visible
S03Relato ABIERTA/sesion/BOB-2604El sur · 14 · CTA activo
S04Relato COMPLETA/sesion/BOB-2603Cría cuervos · CTA disabled
S05Pedir/pedir/BOB-2604 · nombre Luis · submit201 · /ok/BOB-2604
S06Copy successLeer /ok/BOB-26044 oposiciones visibles
S07409Forzar pedir en BOB-2603409 · mensaje butaca
S08Login/login MartaJWT · /mesa
S09Mesa authGET /api/mesa con token4 + pedidos
S10Mesa 401GET /api/mesa sin token401
S11Mobile/ @390Dock · 4 noches · targets
S12SeedTras re-seed3 ABIERTA · 1 COMPLETA

4. Regresión funcional

IDÁreaCheck
R01DecrementoTras POST, remaining −1
R02Autocomplete COMPLETAremaining → 0 ⇒ status COMPLETA
R03Nombre vacío400 · no navega a ok
R04Code inventado/sesion/BOB-9999 · 404 UI
R05Guard ruta/mesa sin token → login ?next=
R06LogoutToken limpio · mesa 401
R07DockCartelera / Pedir / Mesa navegables
R08NoteNote opcional persiste en mesa
R09Público sin nombresJSON sesiones sin name de pedidos
R10Leftover0 lomo-api / ejemplares / BIBLIO en UI

5. Accesibilidad (muestra)

IDCheck
A01Cream sobre velvet en cuerpo (inspección / contraste)
A02Focus visible brass en tab order
A03Dock slots ≥ 44×44
A04Status con texto, no solo color
A05prefers-reduced-motion sin parallax
A06Labels en form pedir y login
A07aria-busy en loading feed

6. Contenido

IDCheck
C01Ningún CTA «Comprar» / «Play» / «Entrada»
C02Eslogan en cartelera
C03COMPLETA = «Completa» no «Agotado» retail
C04Códigos BOB-XXXX

7. Visual / Paper

IDCheck
V01Still a sangre + feed (no hero 2-col)
V02Mood candlelit (no neón multiplex)
V03Covers seed cargan (colmena/golfos/cuervos/sur)
V04Mesa = lista + pedidos (no kanban)

8. API negativa

CasoHTTP
Login malo401
Pedir sin nombre400
Pedir COMPLETA409
Pedir code 404404
Mesa sin auth401

9. Datos de prueba

ActorDato
VecinoLuis Navarro · note «Voy con Inma»
Sesión happyBOB-2604
Sesión bloqueoBOB-2603
PROGRAMADORmarta@bobina.cine

Tras smoke: re-seed para restaurar remaining. [DECISIÓN]

10. Criterio de salida

Smoke S01–S12 en verde. Sin P0 (health mal, pedir roto, mesa abierta sin auth, copy Cinesa ausente en success).
P1 visual puede quedar anotado; no bloquea docs.

11. Fuera de alcance QA v1

Penetration test, auditoría RGPD formal, subtítulos de película, compatibilidad IE, métricas reales de north star instrumentadas.

14-dev-handoff.md

14 — Handoff a desarrollo — BOBINA

1. Contrato vivo

ArtefactoPath
Briefdocs/00-day-brief.md
Paper refdocs/00-paper-reference.md
Productodocs/01-project-definition.md
IA / rutasdocs/03-information-architecture.md
Flujosdocs/04-user-flows.md
Datosdocs/05-data-model.md
Stackdocs/06-tech-stack.md
DS / tokensdocs/08-design-system.md
Copydocs/09-content-guide.md
Builddocs/20-implementation.md
App/Users/cristian/orca/bobina-app
Paper01M0YE7DABVQNCPYK4JQPCSEEQ
Neontiny-feather-31905339
API:3026 · bobina-api

Si código y docs divergen, alinear ambos; no silenciar leftover LOMO como producto. [DECISIÓN]

2. Definition of Done (DoD) L1

#Criterio
1Rutas / /sesion/:code /pedir/:code /ok/:code /login /mesa
2Home = Pliego H-FEED (still + 4 noches), no H-DATA ni hero 2-col
3Dock S-DOCK Cartelera · Pedir · Mesa
4F-STORY: relato antes del form
5POST pedir público; success con 4 oposiciones
6JWT PROGRAMADOR; mesa 401 sin token
7Seed 4 sesiones · 3 ABIERTA · 1 COMPLETA
8Health bobina-api · puerto 3026
9Tokens candlelit + Cormorant/Manrope
10Empty / error / loading
11Mobile 390 usable
120 dominio ejemplares / BIBLIO / lomo-api

3. Mapa Paper → Angular

UIRutaComponente
UI-01 / 02/CarteleraPage
UI-03 / 04/sesion/:codeSesionPage
UI-05/pedir/:codePedirPage
UI-06/ok/:codeOkPage
UI-07/loginLoginPage
UI-08/mesaMesaPage
UI-09 / 10estadosmismos components
UI-11chromeDockComponent

4. API checklist

MétodoRutaAuth
GET/api/healthNo
GET/api/sesionesNo
GET/api/sesiones/:codeNo
POST/api/sesiones/:code/pedirNo
POST/api/auth/loginNo
GET/api/mesaJWT PROGRAMADOR

Body pedir: { name: string, note?: string }.
Decremento atómico de remaining. [DECISIÓN] ver doc 05.

5. Seed y credenciales

ItemValor
Emailmarta@bobina.cine
Passwordpassword123
Hash$2b$12$OEKcNck63neDJ.CrVP0lNOaXp2NG2zd2aMiGmnYY221h4ZAZ58x1m
CodesBOB-2601…2604
Covers/assets/sesiones/{colmena,golfos,cuervos,sur}.jpg

6. Anti-patrones de implementación

No hacerHacer
Puerto 3025 / health lomo-api3026 / bobina-api
Tabla ejemplaressesiones
Comando /buscarFeed only
Kanban mesaLista + pedidos
Pago / StripePOST nombre
Player videoRelato estático
Hero 2-col marketingPliego foto-led

7. Assets

Copiar desde case:

  • assets/sesiones/colmena.jpg
  • assets/sesiones/golfos.jpg
  • assets/sesiones/cuervos.jpg
  • assets/sesiones/sur.jpg
  • assets/hero.jpg (referencia / cover)

[COMPROBADO] existen en el case.

8. QA mínimo antes de merge

Ejecutar smoke S01–S12 (doc 13). Verificar copy irrenunciable en /ok/:code.

9. Open questions (no bloquean L1)

PreguntaDefault
¿Prisma o pg + ensureSchema?ensureSchema válido
¿localStorage vs memory token?localStorage demo OK
¿Note maxlength?280
¿Pedir del dock sin contexto?Primer ABIERTA o prompt

10. Contacto de diseño

Paper file + docs 07–09. No reinventar neón multiplex. Mood candlelit. Ground #1A1210.

15-roadmap.md

15 — Roadmap — BOBINA

1. Horizonte

FaseNombreIntención
L1Slice actualFeed + relato + pedir + mesa JWT · cerrado en alcance
L+1Oficio cercanoMejoras sin romper terna ni microcopy
L4Asociación realSolo si deja de ser demo de portfolio

[DECISIÓN] Este case no implementa L4. El roadmap evita colar VOD/taquilla como «L1 incompleto».

2. Hecho en L1 (Must)

PiezaEstado
H-FEED Pliego 4 nochesMust
F-STORY relatoMust
Pedir butaca sin cuentaMust
Success + 4 oposicionesMust
Login PROGRAMADORMust
Mesa lista + pedidosMust
Empty / error / loading / 390Must
Docs 00–20 + README + executiveMust
Paper 12 UX + 12 UI (inventario)Must (ref)

3. L+1 (Could cercano)

IDIdeaValorRiesgo
L1-01Rate-limit POST pedirAnti-spamComplejidad
L1-02Filtro mesa ABIERTA/COMPLETAOficio MartaScope creep UI
L1-03confirmada_at / vista north star internaMétricaNo instrumentar PII
L1-04Ficha /mesa detalle pedidoLecturaNo kanban
L1-05Skip link + audit axe CIA11y
L1-06Note maxlength + sanitize hardSeguridad
L1-07Dock Pedir con deep-link inteligenteUXNo quinta sesión fantasma
L1-08Re-seed botón solo devDemoNo en prod

Fuera de L+1: pago, Filmin, cuenta de vecino, chat, GPS.

4. L4 (explícitamente otro producto)

IdeaPor qué L4
Taquilla / precio / QRRompe «≠ Cinesa»
VOD / archivo streamingRompe «≠ Filmin»
Multi-sede / multi-programadoraAsociación real
App nativa + pushPlataforma nueva
RCPD completo + exportacionesLegal de org real
Integración FilmotecaAcuerdos reales
Proyeccionista / barra rolesS3 fuera

5. Anti-roadmap (no disfrazar)

Pedido típicoRespuesta
«Pon un player»No · Cartelera ≠ Filmin
«Pon precio»No · Pedir ≠ Cinesa
«Pon búsqueda tipo LOMO»No · rompe terna H-FEED
«Pon kanban»No · ≠ PREGÓN
«Haz L2 de datos»No · N−1 ya fue LOMO

6. Dependencias

DependenciaNota
Neon tiny-feather-31905339L1
Paper fileDiseño; no bloquea docs
bobina-app rewriteParalelo a esta suite
GH Criscode2022/bobina-appRemoto

7. Criterios para abrir L+1

  1. Smoke L1 en verde.
  2. Copy irrenunciable intacto.
  3. Ningún item L+1 introduce pago/VOD/chat.
  4. North star sigue siendo modelo o se instrumenta sin PII.

8. Cierre

L1 está completo en definición. El roadmap no es una lista de deuda disfrazada: es un muro contra el multiplex y el VOD. [DECISIÓN]

16-interaction-specs.md

16 — Especificación de interacción — BOBINA

1. Convenciones

TokenValor
Duración corta120–160ms
Easingease-out
Reduced motion0ms
Target≥44×44
Pendingcontrol disabled + aria-busy

Loading y empty / error viven con los gestos (UI-09 / UI-10). [DECISIÓN]


2. Cartelera feed (UI-01) + mobile (UI-02) · H-FEED Pliego

GestoResultado
Primera cargaLoading: skeleton still + 4 tiles card; aria-busy
200 con 4Still a sangre + 4 tarjetas. Título, noche, butacas, estado
200 con 0UI-09 empty «Aún no hay noches.»
Error 5xx / redUI-10 + Reintentar (repite GET sesiones)
Tap tarjeta/sesion/:code
Tap Mesa (dock)/login o /mesa si hay token
Hover tarjeta desktopRing 2px brass. Sin lift excesivo
Tap Pedir (dock) sin contextoPrimer ABIERTA o prompt «Elige una noche»

AC: título, noche, butacas y estado visibles sin hover. Still ≥40 % del recorte 16/10 (AP-21 / D-P1-09). Cero botones Comprar / Play / Entrada.

El aviso «Cartelera ≠ Filmin» es texto, no un CTA de VOD. [DECISIÓN]

390: mismas 4 tarjetas apiladas. No carousel. Dock visible. [DECISIÓN]


3. Sesión relato (UI-03) + mobile (UI-04) · F-STORY

GestoResultado
Primera cargaLoading: skeleton de relato
200 ABIERTACover, título, director, noche, remaining, blurb, copy × oposiciones, CTA
200 COMPLETAIgual + CTA disabled «Completa. Sin butacas.»
404«Esa sesión no está.»
Tap Pedir butaca/pedir/:code (F-STORY; no POST aquí)
Tap ← Cartelera/

AC: una pantalla de relato. Cero pago. Cero «Ver en Filmin». Cero «Pedir mesa» (LOMO).


4. Pedir (UI-05)

GestoResultado
CargaForm + sesión en solo lectura + disclaimer
Nombre vacío + submit«Escribe un nombre.» · no POST
Submit válidoPOST · pending en botón
201/ok/:code con state
409oxblood + «No se puede pedir esa butaca.»
Redseal + Reintentar; no navega a ok
NoteOpcional; no bloquea submit

AC: no email, no DNI, no pago. Pedir butaca ≠ entrada Cinesa visible.


5. Success (UI-06)

GestoResultado
Entrada desde 201Código BOB-XXXX grande + título + noche + 4 oposiciones
Tap Volver/
Deep link directoMuestra sesión si GET ok; no inventa pedido

AC: las cuatro oposiciones están. No QR. No «ticket listo».


6. Login (UI-07)

GestoResultado
Submit válidoPOST login · guarda JWT · /mesa o next
401«Email o contraseña no valen.»
Guest en /mesaRedirect /login?next=/mesa

AC: sin signup. Ayuda demo mute.


7. Mesa PROGRAMADOR (UI-08)

GestoResultado
Primera cargaLoading skeletons lista + pedidos
2004 sesiones + pedidos (name, code, note, hora)
Empty pedidos«No hay pedidos.»
401Redirect login
SalirLimpia token → /
Tap filaCould L+1; v1 sin /mesa/:code

AC: no columnas Recibido / En curso. No PATCH estado. No split lista|ficha.


8. Dock (UI-11) · S-DOCK

GestoResultado
Tap Cartelera/
Tap PedirContexto sesión ABIERTA → /pedir/:code; si no → prompt / primer ABIERTA
Tap MesaAuth → /mesa; guest → login
ActivoBrass + aria-current
IdleMute

AC: tres slots. No hamburger. Targets ≥44px. Fijo en 390.


9. Empty / Error / Loading (UI-09 / UI-10)

EstadoUI
LoadingPulse card; aria-busy
Empty feedDisplay + mute + sin CTA de Filmin
Empty mesa pedidosMute
ErrorTitular + Reintentar brass

10. Motion

GestoDefaultReduced
Aparición feedFade 140msInstant
Hover ring120msInstant
StillEstáticoEstático

Sin Ken Burns agresivo sobre el Pliego. [DECISIÓN]


11. Guión de interacción demo

  1. / loading → 4 noches + still.
  2. Hover/tap Cría cuervos → relato COMPLETA → CTA disabled.
  3. El sur → Pedir butaca → form Luis → pending → success.
  4. Dock Mesa → login → mesa con pedido.
  5. 390: dock no tapa CTA; scroll con padding.

12. Criterios de aceptación de interacción

  1. F-STORY no salta el relato.
  2. COMPLETA no permite POST.
  3. Pending no doble-envía.
  4. Dock siempre alcanzable en 390.
  5. Focus visible en todo el recorrido teclado.

17-prototype-map.md

17 — Mapa de prototipo — BOBINA

1. Fuentes

FuenteID / path
Paperhttps://app.paper.design/file/01M0YE7DABVQNCPYK4JQPCSEEQ
File ID01M0YE7DABVQNCPYK4JQPCSEEQ
UX-count12
UI-count12
App/Users/cristian/orca/bobina-app
Case assets2026-08-26-bobina/assets/

[COMPROBADO] conteos y file ID en docs/00-paper-reference.md.
Esta entrega de docs no abre Paper ni arranca la app.

2. UX process → docs

UXNombreDoc espejo
UX-00CoverREADME · executive · 07
UX-01Stakeholders02 §3
UX-02Personas02 §4
UX-03JTBD02 §5
UX-04Stories02 §6
UX-05Journey02 §7 · 04
UX-06Blueprint02 §8
UX-07Site map03
UX-08Flujos04
UX-09Datos+permisos05 · 01 §5 · 11
UX-10Métricas12
UX-11Research02

3. UI producto → rutas / componentes

UINombreRutaComponente Angular
UI-00Tokens— (theme)Tailwind config / styles
UI-01Cartelera feed/CarteleraPage
UI-02Cartelera mobile/ @390CarteleraPage
UI-03Sesión/sesion/:codeSesionPage
UI-04Sesión mobile/sesion/:code @390SesionPage
UI-05Pedir/pedir/:codePedirPage
UI-06Success/ok/:codeOkPage
UI-07Login/loginLoginPage
UI-08Mesa PROGRAMADOR/mesaMesaPage
UI-09Emptymismas rutasestados
UI-10Error+Loadingmismas rutasestados
UI-11Dockchrome globalDockComponent

4. Flujo prototipo clickable (orden demo)

UI-01 Cartelera
  ├─→ UI-03 Sesión (BOB-2603 COMPLETA)
  │     └─→ (CTA disabled) → back UI-01
  ├─→ UI-03 Sesión (BOB-2604 ABIERTA)
  │     └─→ UI-05 Pedir → UI-06 Success
  ├─→ UI-02 (mismo /, viewport 390)
  └─→ UI-11 Dock → Mesa → UI-07 Login → UI-08 Mesa

Estados: UI-09 empty · UI-10 error/loading se prueban desconectando API o seed vacío.

5. Datos de prototipo = seed

CodeTítuloEstadoCover asset
BOB-2601El espíritu de la colmenaABIERTAsesiones/colmena.jpg
BOB-2602Los golfosABIERTAsesiones/golfos.jpg
BOB-2603Cría cuervosCOMPLETAsesiones/cuervos.jpg
BOB-2604El surABIERTAsesiones/sur.jpg

Hotspots Paper deben usar estos códigos en labels si muestran URL. [DECISIÓN]

6. Breakpoints de artboard

ArtboardAncho ref
Desktop feed / sesión / mesa~1280–1440
Mobile feed / sesión390
Tokens / docksegún Paper

7. Terna visible en prototipo

CódigoEvidencia en UI
R-INVelvet inmersivo + still a sangre
S-DOCKUI-11 tres slots
H-FEEDUI-01 Pliego
F-STORYUI-03 antes de UI-05

8. Gaps conscientes

GapNotas
Paper no se regenera en esta pasada de docsInventario 00 intacto
Micro-interacciones pendingSpec en 16
Analytics no en prototipoModelo 12

9. Criterios de aceptación del mapa

  1. Cada UI-00…11 tiene fila en esta tabla.
  2. Cada ruta Must tiene artboard.
  3. No hay artboard de /buscar, /lomo, taquilla o player.
  4. Mobile 390 cubierto (UI-02, UI-04).

18-completeness-audit.md

18 — Auditoría de cierre — BOBINA

1. Alcance L1

PiezaEstado
Docs 01–20 + README + executiveOK (este set)
00-day-brief / 00-paper-referenceIntactos (no tocados)
Paper 12 UX + 12 UIInventario en 00 (no se arranca Paper aquí)
App path /Users/cristian/orca/bobina-appOK · rewrite en paralelo
Neon tiny-feather-31905339OK
API :3026 · health bobina-apiContrato (leftover lomo-api prohibido)
Código sesiones + pedidos + JWT PROGRAMADORContrato paralelo
Cierre sin deuda del L1OK · roadmap solo L+1 / L4

2. Terna y diversidad

CheckEvidencia
R-IN · S-DOCK · H-FEED · F-STORYBrief + 01 + 07
0 códigos = LOMOLOMO era R-CL · S-CMD · H-DATA · F-LEAD
≥2 vs ONDA / RAMALDock/Feed/Story vs rail/gallery/search y split/full/onb
S-DOCK, H-FEED, F-STORY no en últimos 5Brief
Ground G-VELVET #1A121000 + 07 + Tailwind
No leftover LOMO0 ejemplares / BIBLIO / comando en el contrato
Mood candlelit ≠ neón multiplex07

3. Copy irrenunciable

Presente en cartelera, relato, pedir, success, pie de mesa. Ver doc 09.

  • Pedir butaca ≠ entrada Cinesa
  • Sesión ≠ estreno
  • Cartelera ≠ Filmin
  • BOBINA no es los cines del centro

4. Anti-patrones vigilados

APMitigación
AP-12 hero 2-colH-FEED Pliego still + feed
AP-21 card huecaTítulo/noche/butacas/estado visibles
Leftover como estadoContrato BOBINA; no se anota LOMO como producto vivo
Entrevistas inventadas02 etiquetado
ejemplares/BIBLIO/lomo-api0 en dominio; 05 + 20
programas/CONDUCTOR/radio0 en dominio
H-DATA / S-CMDFeed + dock; no mesa de datos ni comando
Estadísticas inventadasEtiquetas [HIPÓTESIS]/[SUPUESTO]

5. Seed

4 sesiones · 3 ABIERTA · 1 COMPLETA · Marta PROGRAMADOR · Luis sin cuenta · Inma fuera de login.

codetitlestatusremaining
BOB-2601El espíritu de la colmenaABIERTA12
BOB-2602Los golfosABIERTA8
BOB-2603Cría cuervosCOMPLETA0
BOB-2604El surABIERTA14

6. Assets

ArchivoPresente
assets/hero.jpg[COMPROBADO] case
assets/sesiones/colmena.jpg[COMPROBADO]
assets/sesiones/golfos.jpg[COMPROBADO]
assets/sesiones/cuervos.jpg[COMPROBADO]
assets/sesiones/sur.jpg[COMPROBADO]

7. Huecos conscientes (fuera)

Pago, login Inma, email transaccional, instrumentación analytics, VOD, confirmada_at, player, Filmoteca real.

8. Checklist archivos suite

ArchivoEstado
README.mdOK
presentation/executive-summary.mdOK
docs/01 … docs/20OK
docs/00-*Preexistentes intactos

9. Veredicto

Slice L1 cerrado a nivel de case. El código se escribe en paralelo con el mismo contrato. Si el repo diverge (leftover LOMO), gana docs 05 + 20 tras alinear ambos. Paper no se abre en esta entrega de docs.

19-backlog-completo.md

19 — Backlog completo — BOBINA

1. Leyenda

EstadoSignificado
Done (docs)Definido y aceptado en la suite ALS
Must (build)Obligatorio en el rewrite de bobina-app
Could L+1Opcional cercano sin romper terna
Won’t L1Fuera; ver roadmap L4

2. Épica A — Cartelera H-FEED

IDÍtemEstado
A1Pliego still a sangre + feed 4 nochesDone docs · Must build
A2Tarjeta: título, director, when_label, remaining, statusDone docs · Must build
A3Tap → /sesion/:codeDone docs · Must build
A4Empty / loading / errorDone docs · Must build
A5Mobile 390 + assets coversDone docs · Must build
A6Búsqueda comando /buscarWon’t L1 (≠ LOMO)

3. Épica B — Relato F-STORY

IDÍtemEstado
B1/sesion/:code relato completoDone docs · Must build
B2CTA Pedir butaca si ABIERTADone docs · Must build
B3CTA disabled si COMPLETADone docs · Must build
B4Copy irrenunciable en relatoDone docs · Must build
B5Player / trailerWon’t L1 (≠ Filmin)

4. Épica C — Pedir butaca

IDÍtemEstado
C1/pedir/:code form name + noteDone docs · Must build
C2POST público 201 / 409 / 400 / 404Done docs · Must build
C3Decremento remaining + COMPLETADone docs · Must build
C4/ok/:code + 4 oposicionesDone docs · Must build
C5Pago / QR / precioWon’t L1 (≠ Cinesa)
C6Signup vecinoWon’t L1 (S2)

5. Épica D — Mesa PROGRAMADOR

IDÍtemEstado
D1Login JWT MartaDone docs · Must build
D2/mesa lista + pedidosDone docs · Must build
D3GET mesa 401 sin tokenDone docs · Must build
D4LogoutDone docs · Must build
D5Kanban columnasWon’t L1 (≠ PREGÓN)
D6Filtro estado / ficha pedidoCould L+1

6. Épica E — Chrome S-DOCK

IDÍtemEstado
E1Dock Cartelera · Pedir · MesaDone docs · Must build
E2aria-current + targets 44Done docs · Must build
E3Pedir contextualDone docs · Must build
E4Rail ONDA / comando LOMOWon’t L1

7. Épica F — Design system & a11y

IDÍtemEstado
F1Tokens velvet/cream/card/brass/mute/oxbloodDone docs · Must build
F2Cormorant + ManropeDone docs · Must build
F3Contraste cream/velvet AADone docs · Must build
F4Reduced motionDone docs · Must build
F5Modo letra grande InmaCould L+1

8. Épica G — Plataforma

IDÍtemEstado
G1Nest :3026 · health bobina-apiDone docs · Must build
G2Neon tiny-feather-31905339 schema+seedDone docs · Must build
G3Angular rutas + guardDone docs · Must build
G4pnpm apps independientesDone docs · Must build
G5Instrumentación north starCould L+1
G6Multi-sede / FilmotecaWon’t L1 · L4

9. Épica H — Documentación & diseño

IDÍtemEstado
H1docs 00–20 + README + executiveDone
H2Paper UX 12 + UI 12 inventarioDone ref
H3Regenerar artboards PaperFuera de esta pasada docs

10. Prioridad de build sugerida

  1. Schema + seed + health
  2. GET sesiones + CarteleraPage Pliego
  3. SesionPage + estados ABIERTA/COMPLETA
  4. POST pedir + OkPage copy
  5. Auth + MesaPage
  6. Dock + 390 + empty/error/loading
  7. Pulido tokens / a11y / smoke S01–S12

11. Contadores

TipoCount (aprox)
Must build~35
Could L+1~8
Won’t L1~12
Docs DoneSuite completa

No se inventan story points ni velocidades de equipo. [DECISIÓN]

20-implementation.md

20 — Implementación — BOBINA

1. Resumen ejecutivo técnico

CampoValor
App path/Users/cristian/orca/bobina-app
GHCriscode2022/bobina-app
APINestJS · puerto 3026 · prefijo /api
WebAngular standalone · puerto 4200
Packageapps independientes (pnpm --filter)
DBNeon PostgreSQL · project tiny-feather-31905339
Tablasusers, sesiones, pedidos, sessions
AuthJWT Bearer · role PROGRAMADOR (/mesa); feed y POST pedir públicos
DominioUser, Sesión, Pedido
Fecha2026-08-26
Healthbobina-api (leftover lomo-api → sustituir)

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: sesiones + pedidos + JWT PROGRAMADOR. Puerto 3026. Health bobina-api.

[COMPROBADO] Path, puerto, Neon y Paper salen del encargo.
No se arranca la app ni Paper desde esta entrega de docs.

El repo puede contener leftover LOMO (ejemplares, BIBLIO, HoyPage, lomo-api, puerto 3025) al inicio del rewrite. Eso no es BOBINA. El rewrite borra ese dominio.

2. Cómo arrancar

cd /Users/cristian/orca/bobina-app
# instalar dependencias por app (pnpm --filter; no npm workspaces)

# apps/api/.env
#   DATABASE_URL=<neon tiny-feather-31905339>
#   JWT_SECRET=<secret>
#   PORT=3026

# schema + seed
# api → http://localhost:3026
# web → http://localhost:4200

Credenciales

RolEmailPassword
PROGRAMADORmarta@bobina.cinepassword123

Hash seed: $2b$12$OEKcNck63neDJ.CrVP0lNOaXp2NG2zd2aMiGmnYY221h4ZAZ58x1m

Vecino / vecina mayor: sin cuenta. Luis pide en /pedir/:code. Inma no entra por login.

3. Schema

Al boot o vía migrate:

  1. CREATE TABLE de users, sessions, sesiones, pedidos (doc 05).
  2. Índices: sesiones(code), sesiones(status), sesiones(sort_order), users(email), pedidos(sesion_id), pedidos(created_at DESC).
  3. Seed idempotente:
    • upsert PROGRAMADOR marta@bobina.cine (hash bcrypt canónico)
    • upsert sesiones por code (BOB-2601BOB-2604) restaurando status y remaining de catálogo
    • pedidos: no borrar pedidos de demo recientes salvo re-seed explícito
  4. Dominio: solo sesiones + pedidos + users. [DECISIÓN]

Upsert de sesiones por code restaura status/remaining de catálogo para que el guión sea repetible. [DECISIÓN]

No generar códigos nuevos en el POST: el success reusa BOB-2604.

Tablas (recordatorio)

TablaContenido
usersPROGRAMADOR Marta
sesiones4 noches
pedidosButacas (las del POST)
sessionssid + expires_at

DROP leftover ejemplares, programas, repeticiones, nodes, altas si existen en el mismo Neon. [DECISIÓN] El project tiny-feather-31905339 es de BOBINA.

Seed SQL (modelo)

codetitledirectorwhen_labelseatsremainingstatuscover
BOB-2601El espíritu de la colmenaVíctor Ericejue 27 ago 20:001212ABIERTA/assets/sesiones/colmena.jpg
BOB-2602Los golfosCarlos Sauravie 28 ago 21:0088ABIERTA/assets/sesiones/golfos.jpg
BOB-2603Cría cuervosCarlos Saurasáb 29 ago 19:30120COMPLETA/assets/sesiones/cuervos.jpg
BOB-2604El surVíctor Ericedom 30 ago 18:001414ABIERTA/assets/sesiones/sur.jpg

[SUPUESTO de cartelera] Títulos demo.

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 === PROGRAMADOR protege /mesa.
  • Públicos: health, sesiones, sesiones/:code, POST pedir, login.

Oficio

MétodoRutaAuthNotas
GET/api/healthNo{ ok: true, service: "bobina-api" }
GET/api/sesionesNosort_order asc + remaining + status + cover
GET/api/sesiones/:codeNorelato
POST/api/sesiones/:code/pedirNoINSERT pedido; remaining −1; COMPLETA si 0; 409 si no ABIERTA; 404 si no hay sesión
GET/api/mesaJWT4 sesiones + pedidoCount + lista pedidos

Health (referencia de implementación)

{ "ok": true, "service": "bobina-api" }

Cualquier leftover "lomo-api" o "onda-api" falla el DoD.

POST pedir — algoritmo

1. Validar body.name (trim, length >= 2) else 400
2. SELECT sesión FOR UPDATE by code
3. Si no existe → 404
4. Si status != ABIERTA OR remaining <= 0 → 409
5. INSERT pedidos (sesion_id, code, name, note)
6. UPDATE remaining = remaining - 1
7. Si remaining = 0 → status = COMPLETA
8. 201 { code, title, status, remaining, pedida: true }

Transacción única. [DECISIÓN]

GET mesa — shape

{
  "sesiones": [ { ...sesion, "pedidoCount": n } ],
  "pedidos": [ { "id", "code", "name", "note", "createdAt" } ]
}

Orden pedidos: created_at DESC. [DECISIÓN]

5. Frontend Angular

Rutas

PathComponentGuard
''CarteleraPage
sesion/:codeSesionPage
pedir/:codePedirPage
ok/:codeOkPage
loginLoginPage
mesaMesaPageauthGuard
**redirect ''

Servicios

ServiceResponsabilidad
SesionesApiGET list/detail, POST pedir
AuthApilogin, token store, logout
MesaApiGET mesa con Bearer
DockStateslot activo / contexto pedir

UI Must

  1. CarteleraPage — still + feed overlay (Pliego), no tabla H-DATA.
  2. SesionPage — F-STORY.
  3. PedirPage — form.
  4. OkPage — código + 4 oposiciones.
  5. LoginPage / MesaPage.
  6. DockComponent — S-DOCK.
  7. Estados empty/error/loading.

Tailwind tokens

ground: #1A1210
cream: #F4EDE4
card: #241C18
brass: #C4A574
mute: #8A7A6E
oxblood: #9A3B2F
font-display: Cormorant Garamond
font-sans: Manrope

6. Assets en app

Copiar desde el case a apps/web/public/assets/sesiones/ (o path equivalente servido):

  • colmena.jpg
  • golfos.jpg
  • cuervos.jpg
  • sur.jpg

Paths en DB alineados a /assets/sesiones/.... [DECISIÓN]

7. Checklist anti-leftover

Prohibido en runtimeSustituto
lomo-apibobina-api
puerto 30253026
ejemplaressesiones
BIBLIOPROGRAMADOR
LM-XXXXBOB-XXXX
/buscar /lomo/ /sesion
DISPONIBLE/EN_SALA/PEDIDOABIERTA/COMPLETA
Source Serif / Outfit mineralCormorant / Manrope candlelit
G-STONE #E4E0D6G-VELVET #1A1210

8. DoD técnico (merge)

  1. Smoke S01–S12 (doc 13) en verde.
  2. Health bobina-api.
  3. Seed idempotente.
  4. Mesa 401 sin token.
  5. Success muestra las 4 oposiciones.
  6. 390 + dock usable.
  7. 0 referencias de producto a ejemplares/BIBLIO/lomo-api.
  8. Cream sobre velvet en cuerpo.

9. Fuera de esta especificación

  • Deploy Vercel/Netlify (Could).
  • CI axe completo (Could L+1).
  • Instrumentación analytics (doc 12 modelo).
  • Regeneración Paper (fuera de docs-only).

10. Cierre

Implementación = contrato ejecutable. Esta suite de docs es la fuente de verdad del case 2026-08-26-bobina mientras el rewrite corre en paralelo. [COMPROBADO] alcance docs-only del encargo.