00-day-brief.md
00 — Day brief · 2026-08-26 · BOBINA
Decisiones ALS-2 BRIEF
| Campo | Valor |
|---|---|
| Fecha | 2026-08-26 |
| Nombre | BOBINA |
| Complejidad | Nivel 1 (no L2 consecutivo tras LOMO) |
| Sector | Cultura / cineclub de barrio (Vallecas) |
| Tipo | Cartelera feed de sesiones + petición de butaca + mesa PROGRAMADOR JWT |
| Plataforma | Web responsive (feed en el móvil · mesa en el portátil de la asociació) |
| Registro | R-IN — dock flotante + feed sobre foto a sangre |
| Shell | S-DOCK — dock fijo: Cartelera · Pedir · Mesa |
| Home | H-FEED foto-led Pliego — still a sangre + cronología de noches |
| Flujo | F-STORY — cada sesión es un relato (noche + película + butacas) y luego el CTA |
| Por qué no LOMO | No S-CMD / H-DATA / F-LEAD; no archivo; no mineral; no mesa de ejemplares |
| Por qué no ONDA | No radio; no H-GALLERY; no S-RAIL |
| Por qué no ATRIO | No 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:
#1A1210terciopelo (ground)#F4EDE4crema de ficha#241C18asiento / card#C4A574latón (mark)#8A7A6Emute#9A3B2Foxblood (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
- Home feed foto-led: 4 sesiones
- Relato de sesión (noche + película + butacas)
- Pedir butaca (pedir ≠ entrada Cinesa)
- Success con copy duro
- Login JWT PROGRAMADOR
- Mesa de noches + pedidos
- Empty / error / loading / mobile feed
- ≥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
| ID | Señal |
|---|---|
| H1 | Un feed de noches reduce «¿qué echan hoy?» por WhatsApp |
| H2 | Separar butaca de entrada Cinesa evita el conflicto con el multiplex |
| H3 | Cuatro sesiones bastan; no hace falta un VOD |
Seed demo
| Código | Título | Noche | Butacas | Estado |
|---|---|---|---|---|
| BOB-2601 | El espíritu de la colmena | jue 27 ago 20:00 | 12 | ABIERTA |
| BOB-2602 | Los golfos | vie 28 ago 21:00 | 8 | ABIERTA |
| BOB-2603 | Cría cuervos | sáb 29 ago 19:30 | 0 | COMPLETA |
| BOB-2604 | El sur | dom 30 ago 18:00 | 14 | ABIERTA |
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
| URL | https://app.paper.design/file/01M0YE7DABVQNCPYK4JQPCSEEQ |
| File ID | 01M0YE7DABVQNCPYK4JQPCSEEQ |
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)
| ID | Nombre | Contenido |
|---|---|---|
| UX-00 | Cover | BOBINA · «La butaca, no la taquilla.» · R-IN · S-DOCK · H-FEED · F-STORY · L1 cineclub · candlelit · 2026-08-26 |
| UX-01 | Stakeholders | PROGRAMADOR Marta, VECINO Luis, proyección fuera, Filmoteca fuera |
| UX-02 | Personas | Marta Ruiz 41 · Luis Navarro 34 · Inma Peña 68 (docs) |
| UX-03 | JTBD | Job «saber qué noche hay butaca sin preguntar por WhatsApp» |
| UX-04 | Stories | Must: feed, relato, pedir, login, mesa, estados |
| UX-05 | Journey | Calle → still de sala → Cría cuervos completa → El sur → pedir butaca |
| UX-06 | Blueprint | Frontstage sala · backstage Neon/JWT |
| UX-07 | Site map | / feed · /sesion/:code · /pedir/:code · /ok/:code · /login · /mesa |
| UX-08 | Flujos | F-STORY público; mesa PROGRAMADOR |
| UX-09 | Datos | User PROGRAMADOR · Sesión; JWT en /mesa |
| UX-10 | Métricas | North star % de noches con butaca pedida antes de las 18:00 |
| UX-11 | Research | Comprobado / supuesto / hipótesis / decisión |
UI producto (prefijo UI- · mínimo 10)
| ID | Nombre | Flujo |
|---|---|---|
| UI-00 | Tokens | DS candlelit: velvet, brass, oxblood |
| UI-01 | Cartelera feed | Pliego: still a sangre + feed de 4 noches · recorte 16/10 |
| UI-02 | Cartelera mobile | 390 · dock |
| UI-03 | Sesión | Relato El espíritu de la colmena |
| UI-04 | Sesión mobile | 390 |
| UI-05 | Pedir | Form butaca |
| UI-06 | Success | Pedida. Butaca ≠ entrada Cinesa |
| UI-07 | Login | JWT PROGRAMADOR |
| UI-08 | Mesa PROGRAMADOR | Lista + pedidos |
| UI-09 | Empty | Sin noches |
| UI-10 | Error+Loading | Red / skeletons |
| UI-11 | Dock | S-DOCK Cartelera · Pedir · Mesa |
Mapeo Paper → Angular
| Artboard | Ruta | Componente |
|---|---|---|
| UI-01 Cartelera | / | CarteleraPage |
| UI-03 Sesión | /sesion/:code | SesionPage |
| UI-05 Pedir | /pedir/:code | PedirPage |
| UI-06 Success | /ok/:code | OkPage |
| UI-07 Login | /login | LoginPage |
| UI-08 Mesa | /mesa | MesaPage |
01-project-definition.md
01 — Definición de proyecto — BOBINA
1. Identidad
| Campo | Valor |
|---|---|
| Nombre | BOBINA |
| Significado | Bobina 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 frase | Cartelera feed foto-led de noches + relato de sesión + petición de butaca + mesa PROGRAMADOR JWT. |
| Sector | Cultura / cineclub de barrio (Vallecas, Madrid) |
| Tipo | Web L1 — feed H-FEED Pliego + dock S-DOCK + story F-STORY + mesa JWT — Nivel 1, vertical slice de cineclub |
| Plataforma | Web responsive (feed en el móvil · mesa en el portátil de la asociación) |
| Mercado demo | España · Madrid · Vallecas (un cineclub de barrio, no los cines del centro) |
| Idioma | es-ES |
| Fecha caso | 2026-08-26 |
| Terna | R-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
| Problema | Quién lo sufre | Efecto |
|---|---|---|
| «¿Qué echan hoy?» por WhatsApp | VECINO (Luis) | Pregunta, espera, se pierde la noche |
| Pedir butaca se lee como entrada Cinesa | VECINO + Marta | Esperan precio, fila, código QR de multiplex |
| La home se lee como Filmin | Luis | Esperan catálogo VOD, play, archivo en streaming |
| Pedir se lee como estreno | Luis + Inma | Esperan cartelera comercial, fecha de estreno |
| La mesa PROGRAMADOR se lee como kanban | PROGRAMADOR (Marta) | Esperan Recibido / En curso / Cerrado |
| El dueño pide VOD y taquilla el día 1 | Asociación | El 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
| ID | Hipótesis | Señal de validación (futura) |
|---|---|---|
| H1 | Un feed de noches reduce «¿qué echan hoy?» por WhatsApp | % de visitas a / que terminan en POST /pedir |
| H2 | Separar butaca de entrada Cinesa evita el conflicto con el multiplex | ↓ «pensé que compraba entrada»; copy visible en success |
| H3 | Cuatro sesiones bastan; no hace falta un VOD | 0 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
| Para | Valor |
|---|---|
| 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 BOBINA | Una superficie mínima: cartelera + relato + mesa, sin Cinesa y sin Filmin. |
No es BOBINA
| Excluido | Por qué |
|---|---|
| Taquilla Cinesa / ticket / QR multiplex | Pedir butaca ≠ entrada Cinesa |
| Filmin / VOD / archivo en streaming | Cartelera ≠ Filmin |
| Estreno comercial / circuito | Sesión ≠ estreno |
| Cines del centro / multiplex | BOBINA no es los cines del centro |
| Catálogo completo / miles de títulos | H3 · S1 |
| Chat de vecinos / kanban | Eso fue PREGÓN (H-CHAT / F-KAN) |
| Quiosco de horas / bloques de 2 h | Eso fue TEMPLE (H-KIOSK / F-BOOK) |
| Galería de cubiertas / archivo de radio | Eso fue ONDA (H-GALLERY / F-SEARCH) |
| Mesa de ejemplares + comando | Eso fue LOMO (H-DATA / S-CMD / F-LEAD) |
| Portada de nodos + checklist de alta | Eso 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 CMS | L1 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
| Rol | Objetivo medible en demo |
|---|---|
| VECINO | Ver 4 noches, tocar El sur, pedir butaca y ver el success en < 90 s, sin cuenta |
| PROGRAMADOR | Entrar a mesa, ver 4 sesiones, leer BOB-2604 y los pedidos en < 45 s |
| VECINA MAYOR | No 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ón | Anónimo (vecino) | PROGRAMADOR | VECINA MAYOR |
|---|---|---|---|
Ver cartelera / | Sí | Sí | Sin cuenta; usa la pública |
Ver relato /sesion/:code | Sí | Sí | — |
Ver form /pedir/:code | Sí | Sí (no es el job) | — |
| POST pedir butaca | Sí | Sí (no es el job) | Sí (mismo form público) |
Ver success /ok/:code | Sí (código en URL) | Sí | — |
Ver mesa /mesa | No (401 / redirect) | Sí | No |
GET /api/mesa | 401 | Sí | — |
| Ver lista de pedidos | No | Sí (mesa) | — |
| Vender entrada Cinesa | No (no existe) | No | Fuera |
| Proyectar / barra | Copy: fuera | Copy: fuera | Oficio 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)
| Tipo | Métrica | Definición |
|---|---|---|
| North Star | % de noches ABIERTA con ≥1 pedido antes de las 18:00 | Oficio de sala, no pageviews |
| Activación vecino | 1.er POST /pedir con code | H1 |
| Integridad de expectativa | Reclamaciones «¿compro entrada?» / «¿es Filmin?» / «¿es estreno?» | H2 + microcopy |
| Integridad de auth | GET /api/mesa sin token → 401; POST /api/sesiones/:code/pedir sin token → 201 | Feed público + mesa PROGRAMADOR cerrada |
| Salud | Error rate API sesiones / pedidos | 4xx/5xx |
7. Alcance funcional v1 (L1)
| Módulo | Incluido |
|---|---|
| Cartelera feed | GET /api/sesiones · still a sangre + 4 noches |
| Relato | GET /api/sesiones/:code · título, director, noche, butacas, blurb |
| Pedir | POST /api/sesiones/:code/pedir → success; butaca ≠ Cinesa |
| Auth | POST /api/auth/login → JWT PROGRAMADOR |
| Mesa PROGRAMADOR | GET /api/mesa JWT · lista + pedidos, no kanban |
| Estados UI | Empty (0 noches), loading skeleton, error de red |
| Mobile | Feed ~390px · dock Cartelera · Pedir · Mesa · targets ≥44px |
| Seed | 1 PROGRAMADOR, 4 sesiones (3 ABIERTA, 1 COMPLETA) |
| Salud | GET /api/health → { ok: true, service: "bobina-api" } |
8. Criterios de aceptación de producto
/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.- Un vecino puede ver 4 sesiones, tocar El sur, pedir butaca y obtener success en
/ok/BOB-2604. /ok/:codedice explícitamente que pedir butaca no es entrada Cinesa y que sesión no es estreno.- La UI dice explícitamente que cartelera no es Filmin y que BOBINA no es los cines del centro.
- Sin token, GET
/api/mesaresponde 401. POST/api/sesiones/:code/pediry GET/api/sesionesson públicos. - Un POST de pedir no crea user, no cobra, no abre Filmin, no mueve kanban.
- Un PROGRAMADOR inicia sesión y ve 4 sesiones (3 ABIERTA, 1 COMPLETA) en el seed.
- El tablero autenticado es una mesa de lista + pedidos. No es un kanban de 3 columnas. No es un split lista | ficha.
- Fotos reales en las cubiertas seed (assets
sesiones/*). - Chrome S-DOCK: Cartelera · Pedir · Mesa. Feed sin top-nav de marketing y sin comando de archivo.
- Rutas solo las del doc 03. No existen
/buscar,/lomo,/programa,/hoyJWT de ONDA,/nodos,/alta. GET /api/healthdevuelveservice: "bobina-api"(nolomo-api, noonda-api).- El feed público no muestra nombres de otros vecinos; la mesa PROGRAMADOR sí muestra pedidos con nombre.
- Cría cuervos (BOB-2603) aparece COMPLETA con 0 butacas; no se puede pedir.
9. Stack y artefactos
| Capa | Detalle |
|---|---|
| Frontend | Angular + Tailwind · puerto 4200 |
| Backend | NestJS · puerto 3026 |
| DB | Neon PostgreSQL · project tiny-feather-31905339 |
| Auth | JWT (PROGRAMADOR) |
| Diseño | Paper 01M0YE7DABVQNCPYK4JQPCSEEQ |
| Repo app | /Users/cristian/orca/bobina-app/ · GH Criscode2022/bobina-app |
| Package | pnpm |
[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
| Riesgo | Impacto | Mitigación v1 |
|---|---|---|
| Expectativa de Cinesa | «¿Compro la entrada?» | Copy «Pedir butaca ≠ entrada Cinesa» |
| Expectativa de Filmin | Play, VOD, archivo | Copy «Cartelera ≠ Filmin» |
| Expectativa de estreno | Circuito comercial | Copy «Sesión ≠ estreno» |
| Expectativa de centro | Multiplex, taquilla | Copy «BOBINA no es los cines del centro» |
| Expectativa de kanban | Recibido / En curso | Lista + pedidos, no columnas de estado |
| Leftover LOMO | ejemplares, BIBLIO, lomo-api | Contrato BOBINA; health bobina-api; 0 copy de archivo |
| Leftover ONDA | programas, CONDUCTOR, radio | Dominio sesiones + pedidos + PROGRAMADOR |
| VOD el día 1 | Alcance L4 disfrazado | H3: cuatro noches |
| Cuenta de vecino | Rompe S2 | Sin signup; POST público con nombre de sala |
| Home percibida como landing de cine | Pérdida de H-FEED / AP-12 | Pliego still + feed; no hero 2-col |
| Home percibida como mesa de datos | Confundir con LOMO | H-FEED; no métricas tabulares ni comando |
| Confundir con ONDA (galería + archivo) | Expectativa de cubierta / repetición | Feed de noches; no cubiertas 16/10 de radio |
| Confundir con TEMPLE (kiosk + horas) | Expectativa de bloques de 2 h | Pedir butaca de una sesión; no slots |
| 0 sesiones | Feed vacío sin oficio | Empty «Aún no hay noches.» |
| WhatsApp paralelo | H1 no se mide | North star etiquetada como modelo |
| Brass como texto de párrafo | Contraste WCAG | Brass pinta CTA/foco; cream escribe sobre velvet |
11. Glosario
| Término | Definición en BOBINA |
|---|---|
| Bobina | Rollo / proyección en sala; el producto, no el ticket ni el stream |
| Sesión | Noche programada (sesiones); no es un estreno comercial |
| Código | BOB-XXXX; identifica la sesión |
| Butaca | Plaza física en sala; no es entrada Cinesa |
| Cartelera | Superficie H-FEED pública de noches; feed sobre still |
| Mesa (PROGRAMADOR) | Superficie JWT de Marta (lista + pedidos, no kanban) |
| Pedido | POST 201; no significa ticket ni Filmin |
| Success | Código (BOB-XXXX); no es un QR de multiplex |
| Abierta | Estado ABIERTA; quedan butacas |
| Completa | Estado COMPLETA; 0 butacas restantes |
| Dock | Chrome S-DOCK: Cartelera · Pedir · Mesa |
| PROGRAMADOR | Usuario autenticado que opera la mesa |
| VECINO | Autor/autora del pedido; no tiene fila en users |
| VECINA MAYOR | Persona de docs / a11y; fuera del login |
| Cinesa | Multiplex; fuera. Pedir ≠ entrada |
| Filmin | VOD; fuera. Cartelera ≠ Filmin |
| Centro | Cines del centro; fuera. BOBINA no es el centro |
| Candlelit | Mood: velvet + latón, no neón de multiplex |
| Ground | Terciopelo #1A1210 |
| Cream | Texto / ficha #F4EDE4 |
| Card | Asiento #241C18 |
| Brass | Latón #C4A574 |
| Mute | #8A7A6E |
| Oxblood | Sello #9A3B2F, poco |
| Pliego | Home foto-led: still a sangre + feed overlay |
12. Decisiones de diseño (cierre de brief)
| ID | Decisión | Alternativa descartada |
|---|---|---|
| D1 | Home = feed foto-led Pliego (H-FEED) | Hero 2-col + 3 cards (AP-12) · mesa de datos (LOMO) · galería (ONDA) · search-first |
| D2 | Shell dock Cartelera · Pedir · Mesa (S-DOCK) | Comando de archivo · rail de radio · split mesa · kiosk mínimo |
| D3 | Registro inmersivo de sala a oscuras (R-IN) | Neón de multiplex (primer instinto) · mineral LOMO · signage ONDA |
| D4 | Flujo F-STORY (relato → CTA) | F-LEAD, F-SEARCH como home, F-BOOK, F-KAN, F-ONB |
| D5 | Mood candlelit | Neón de cine (primer instinto), chapel, rusted, subterranean |
| D6 | Un rol autenticado PROGRAMADOR | Multi-rol proyeccionista / vecino / barra |
| D7 | Status ABIERTA / COMPLETA | Kanban de 3 columnas; «vendida»; «en Filmin» |
| D8 | Vecino sin cuenta | Signup, socio, carnet de cineclub |
| D9 | Feed público no lista nombres de vecinos | Tablero público enumerable |
| D10 | POST público de pedir con nombre de sala | Formulario de DNI + pago + ticket |
| D11 | Ground G-VELVET #1A1210 | G-STONE, G-SIGN, G-ICE, G-INK, G-FOG |
| D12 | Success en /ok/:code | Toast único sin pantalla |
| D13 | Relato en /sesion/:code antes del form | POST oculto en la tarjeta del feed (rompería F-STORY) |
| D14 | Mesa PROGRAMADOR = lista + pedidos, no kanban ni split | Recibido / En curso / Cerrado; lista | ficha RAMAL |
| D15 | Feed público + mesa JWT (no auth-first total) | Todo cerrado (rompería S2) · todo abierto (rompería mesa) |
| D16 | Sin taquilla / Filmin | Precio + QR + play |
| D17 | Leftover LOMO no es el producto | Mantener ejemplares / BIBLIO / lomo-api |
| D18 | Health bobina-api · puerto 3026 | leftover lomo-api · :3025 |
13. Relación con el día anterior
| Case | Terna | Por qué BOBINA no lo copia |
|---|---|---|
| LOMO (N−1) | R-CL · S-CMD · H-DATA · F-LEAD | No archivo, no ejemplares, no comando, no BIBLIO, no mesa de datos |
| ONDA (N−2) | R-HY · S-RAIL · H-GALLERY · F-SEARCH | No radio, no cubiertas, no repetición, no CONDUCTOR, no rail |
| RAMAL (N−3) | R-CL · S-SPLIT · H-FULL · F-ONB | No telecom, no nodos, no altas, no vocal, no split |
| TEMPLE (N−4) | R-HY · S-MIN · H-KIOSK · F-BOOK | No kiosk, no horas, no concierto; butaca ≠ coger sala de ensayo |
| PREGÓN (N−5) | R-IN · S-SIDE · H-CHAT · F-KAN | Comparte 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)
| Objetivo | Método en este caso | Salida |
|---|---|---|
| Entender actores del cineclub | Modelado 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 feed | Journey + service blueprint | §7–8 |
| Traducir a requisitos L1 feed + relato + pedir + mesa | Matriz 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
| Prohibido | Permitido |
|---|---|
| «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 real | Quotes de persona etiquetadas como constructo de diseño |
| Volumen medido «23 butacas/semana de El sur» como KPI de mercado | Sesiones de seed de producto, etiquetadas como demo |
| Programación oficial de un cineclub de Vallecas 2026 | Sesiones 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
| Stakeholder | Influencia | Interés | Necesidad principal |
|---|---|---|---|
| PROGRAMADOR (Marta) | Alta | Muy alta | Ver noches y pedidos sin kanban ni Filmin |
| VECINO (Luis) | Alta en la butaca | Muy alta | Saber qué noche hay butaca, sin cuenta |
| VECINA MAYOR (Inma) | Media formal, baja en producto día 1 | Alta | Leer la cartelera con contraste y targets; sin login forzado |
| Asociación / cineclub de barrio | Alta formal | Alta | Que se vea qué hay esta semana; que no se confunda con Cinesa ni Filmin |
| Cinesa / multiplex | Competencia / analogía falsa | — | Fuera de alcance; no clonar taquilla |
| Filmin / VOD | Canal paralelo / analogía falsa | — | Fuera; Cartelera ≠ Filmin |
| Filmoteca / cines del centro | Analogía falsa de circuito | — | Fuera; BOBINA no es el centro |
| LOMO / sala de lectura | Anti-patrón N−1 | — | Fuera; no ejemplares, no BIBLIO, no comando |
| ONDA / radio | Anti-patrón N−2 | — | Fuera; no programas, no CONDUCTOR, no antena |
| Grupo de WhatsApp del barrio | Canal paralelo | — | No 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
| Campo | Detalle |
|---|---|
| Edad / contexto | 41 años; programa el cineclub en Vallecas; mesa de noches, no de taquilla |
| Digital | Fluida en desktop de asociación; la cartelera pública no es su herramienta principal, pero la mira |
| Goals | Ver qué noches están abiertas, cuáles completas, quién ha pedido butaca |
| Pains | WhatsApp 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 demo | marta@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
| Campo | Detalle |
|---|---|
| Edad / contexto | 34 años; vive en Vallecas; va al cineclub cuando hay butaca; no quiere «otra cuenta de cine» |
| Digital | Móvil desde el portal o el sofá; no se hace socio si puede evitarlo |
| Goals | Ver qué echan esta semana; abrir el relato; pedir butaca; llevarse un código |
| Pains | El 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)
| Campo | Detalle |
|---|---|
| Edad / contexto | 68 años; vecina de Vallecas; lee la cartelera con calma; contraste y tamaño importan |
| Digital | No tiene login en el slice L1; usa la superficie pública si el contraste y los targets aguantan |
| Goals | Entender qué noche hay, sin mistificarse con Cinesa ni Filmin |
| Pains | Texto 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
| Job | Por qué no |
|---|---|
| Comprar entrada de multiplex | Pedir butaca ≠ entrada Cinesa · S4 |
| Ver un VOD / archivo en streaming | Cartelera ≠ Filmin |
| Ir a un estreno comercial | Sesión ≠ estreno |
| Sustituir a los cines del centro | BOBINA 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)
| ID | Como | Quiero | Para |
|---|---|---|---|
| US-01 | Vecino | Ver feed foto-led de 4 noches | Distinguir cartelera de Filmin / Cinesa |
| US-02 | Vecino | Abrir relato (noche + película + butacas) | Saber si está abierta o completa |
| US-03 | Vecino | Pedir butaca y ver success BOB-XXXX | Dejar constancia, no comprar ticket |
| US-04 | Programadora | Entrar con JWT | Abrir la mesa de pedidos |
| US-05 | Programadora | Ver lista de noches + pedidos | Oficio sin kanban |
| US-06 | Ambos | Ver empty / error / loading | No quedarse en blanco |
| US-07 | Vecino | Usar el dock en 390 | Cartelera · Pedir · Mesa sin hamburger |
Could (fuera de L1): login de Inma, pago, VOD, chat, cuenta de vecino, Filmoteca.
7. Journey (resumen)
- Luis abre
/. Ve still a sangre + feed de 4 noches. Cría cuervos COMPLETA; El sur ABIERTA. [H1] - Toca Cría cuervos →
/sesion/BOB-2603. Lee 0 butacas, COMPLETA. CTA disabled. - Vuelve / toca El sur →
/sesion/BOB-2604. Lee 14 butacas, ABIERTA. Copy irrenunciable. - Toca Pedir butaca →
/pedir/BOB-2604. Escribe su nombre. POST →/ok/BOB-2604. Lee las cuatro oposiciones. - Marta entra a
/login→/mesa. Lista + pedidos. - 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)
| Capa | Qué 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. |
| Soporte | Nest · Neon tiny-feather-31905339 · JWT PROGRAMADOR · Paper candlelit |
9. Matriz hallazgo → requisito → feature
| Hallazgo (etiquetado) | Requisito | Feature v1 |
|---|---|---|
| [HIPÓTESIS H1] Feed de noches reduce WhatsApp | 4 noches en fold sobre still | / H-FEED Pliego |
| [HIPÓTESIS H2] Butaca ≠ Cinesa evita el multiplex | Copy irrenunciable + POST que no cobra | /pedir/:code + /ok/:code |
| [HIPÓTESIS H3] Cuatro sesiones bastan | Sin VOD | Seed 4 · no Filmin |
| [SUPUESTO S2] Sin cuenta de vecino | POST público | POST /api/sesiones/:code/pedir |
| [SUPUESTO S3] Una programadora | Un rol JWT | PROGRAMADOR |
| [DECISIÓN S4] Sin Cinesa / Filmin / GPS / chat | No pago, no play, no mapa, no hilo | Fuera 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
| Principio | Aplicación |
|---|---|
| Feed first | La home es still a sangre + 4 noches. No hay landing de marca por delante. No hay mesa de datos. |
| Público / mesa | Luis pide butaca sin cuenta; Marta entra con JWT |
| Feed → relato → form → success | Profundidad 3 desde la cartelera hasta el código (F-STORY) |
| Cada sesión es un relato | F-STORY: noche + película + butacas antes del CTA |
| Mesa PROGRAMADOR = lista + pedidos | Una columna + recuento; no kanban, no split lista | ficha |
| Lenguaje de dominio | Sesión, butaca, noche, pedido, mesa — no «ticket», «VOD», «lomo», «ejemplar» |
| Pedir no es comprar | El success no tiene precio ni QR de multiplex |
| Cartelera no es Filmin | No hay play, no hay archivo en streaming |
| Chrome de oficio | S-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
| Audiencia | Nodos relevantes |
|---|---|
| VECINO | Cartelera → Sesión → Pedir → Ok. No ve /mesa |
| PROGRAMADOR | Login → Mesa · (puede leer la cartelera y los relatos) |
| VECINA MAYOR | Cartelera / 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 sí es ruta (/sesion/:code): F-STORY necesita URL compartible y un paso antes del form. [DECISIÓN]
El form sí 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)
| Slot | Destino | Visibilidad | Notas |
|---|---|---|---|
| Cartelera | / | Todos | Vuelve al feed Pliego. No es hero de marca |
| Pedir | Última sesión ABIERTA o prompt | Todos | Atajo al form; si no hay contexto → cartelera |
| Mesa | /mesa | PROGRAMADOR; si guest → /login?next=/mesa | Oficio 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)
| Elemento | Destino | Notas |
|---|---|---|
| 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/:code | 4 noches; título, noche, butacas, estado |
| Dock Mesa (mute) | /login o /mesa si hay token | Oficio, 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)
| Slot | Destino | Notas |
|---|---|---|
| ← Cartelera | / | Un paso atrás, no stepper de 5 |
| Relato | /sesion/:code | Noche + película + butacas + blurb |
| Pedir butaca | /pedir/:code | Form; no wizard 1—2—3 |
| Enviar | POST → /ok/:code | Una acción |
Chrome de mesa (/mesa autenticado)
| Slot | Destino | Visibilidad | Notas |
|---|---|---|---|
| Mesa | /mesa | Auth | Titular de oficio |
| Lista | — | Auth | Sesiones de la semana |
| Pedidos | — | Auth | Nombre + código; no columnas |
| Cartelera | / | Auth | Secundario vía dock |
| Salir | limpia token → / | Auth | Cabecera 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)
| Concepto | Label |
|---|---|
| Home | Cartelera (no «Inicio», no «Hoy» tipo LOMO, no «Galería») |
| Relato | Sesión (no «lomo», no «programa», no «track») |
| Form | Pedir butaca |
| Success | Pedida / código |
| Staff | Mesa (no «Backoffice», no «Kanban», no «Hoy» JWT ONDA) |
| Auth | Programadora (no «Área cliente», no «Bibliotecaria») |
| CTA | Pedir 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
| Ruta | Qué hay | Qué no hay |
|---|---|---|
/ | Still, eslogan, 4 tarjetas, dock | Precios, login de vecino, play Filmin, métricas tabulares |
/sesion/:code | Cover, título, director, noche, butacas, blurb, CTA | Ticket, follow, player |
/pedir/:code | Nombre, sesión en solo lectura, disclaimer | DNI, email, pago, socio |
/ok/:code | Código + 4 oposiciones | Contrato, ticket, «ya está inscrito» |
/login | Email / clave PROGRAMADOR | Signup de vecino |
/mesa | Lista de 4 + pedidos | Columnas Recibido / En curso; split ficha |
6. Error / empty / loading (sitio)
Viven en las mismas rutas, no en URLs extra.
| Estado | Superficie |
|---|---|
| Loading | Skeletons 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 |
| Completa | CTA 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
| Pieza | Forma |
|---|---|
| Sesión | BOB-2601 … BOB-2604 (BOB versales, guion, 4 dígitos) |
| Relato | /sesion/BOB-2604 |
| Pedir | /pedir/BOB-2604 |
| Success | /ok/BOB-2604 |
9. Mapa Paper → rutas
| Artboard | Ruta | Componente |
|---|---|---|
| UI-01 Cartelera feed | / | CarteleraPage |
| UI-02 Cartelera mobile | / @390 | CarteleraPage |
| UI-03 Sesión | /sesion/:code | SesionPage |
| UI-04 Sesión mobile | /sesion/:code @390 | SesionPage |
| UI-05 Pedir | /pedir/:code | PedirPage |
| UI-06 Success | /ok/:code | OkPage |
| UI-07 Login | /login | LoginPage |
| UI-08 Mesa | /mesa | MesaPage |
| UI-09 Empty | mismas rutas | estados |
| UI-10 Error+Loading | mismas rutas | estados |
| UI-11 Dock | chrome global | DockComponent |
[COMPROBADO] Mapeo alineado a docs/00-paper-reference.md.
04-user-flows.md
04 — Flujos de usuario — BOBINA
1. Convenciones
| Token | Significado |
|---|---|
| F-STORY | Relato de sesión antes del CTA; la home no es el form |
| Mesa | Lista PROGRAMADOR, JWT |
| 201 | Pedido creado (pedida) |
| 409 | Sesión COMPLETA o sin remaining |
| 401 | Mesa sin token |
| 404 | Sesió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-2604muestra las cuatro oposiciones.- El paso
/sesion/:codeexiste: F-STORY no es un POST oculto en el feed. [DECISIÓN] - El paso
/pedir/:codeexiste: 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,
/mesaredirige a/login?next=/mesa. - GET
/api/mesasin 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
| Estado | Trigger | UI |
|---|---|---|
| Loading cartelera | GET sesiones en vuelo | Skeletons de still + 4 tarjetas |
| Empty cartelera | 200 [] | «Aún no hay noches.» |
| Error cartelera | 5xx / red | Reintentar |
| Loading sesión | GET :code | Skeleton de relato |
| 404 sesión | código inexistente | «Esa sesión no está.» |
| Loading pedir | — | Form listo; submit pending |
| 409 pedir | COMPLETA o remaining 0 | «No se puede pedir esa butaca.» |
| Loading mesa | GET mesa en vuelo | Skeletons de fila + pedidos |
| Empty mesa | 200 { pedidos: [] } | «No hay pedidos.» (las 4 filas pueden existir) |
| Login 401 | credenciales | «Email o contraseña no valen.» |
6. Flujos que no existen
| Flujo | Por qué |
|---|---|
| Signup vecino | S2 · Pedir ≠ socio |
| Comprar entrada Cinesa | S4 · Pedir butaca ≠ entrada |
| Ver en Filmin / play | Cartelera ≠ Filmin |
| Chat | ≠ PREGÓN |
| Alta de nodo | ≠ RAMAL |
| Pedir repetición | ≠ ONDA |
| Pedir mesa de lomo / comando | ≠ LOMO |
| Wizard 1—2—3 | Pedir es un form corto |
| Login Inma | Slice L1 · docs / a11y |
| PATCH estado de sesión | Marta lee; no mueve columnas en v1 |
| Catálogo VOD completo | H3 · S4 |
| Coger slot de 2 h | ≠ TEMPLE |
Búsqueda ?q= | Sin S-CMD |
7. Tiempos de demo (modelo)
| Actor | Recorrido | Techo |
|---|---|---|
| Luis | Cartelera → El sur → pedir → pedida | < 90 s |
| Luis (completa) | Cartelera → Cría cuervos → vuelve → El sur | < 90 s |
| Marta | Login → 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
/— still a sangre + 4 noches. Cría cuervos COMPLETA. El sur ABIERTA. Eslogan. Dock.- Tap Cría cuervos — relato COMPLETA · 0 butacas · CTA disabled.
- Tap El sur — relato ABIERTA · 14 butacas · director Erice.
- Pedir butaca —
/pedir/BOB-2604· nombre Luis Navarro · note opcional. - Enviar —
/ok/BOB-2604. Copy ×4. /login—marta@bobina.cine/password123./mesa— lista + pedidos; BOB-2604; pedido de Luis si se hizo el POST.- 390: feed + dock; no carousel; targets ≥44px.
- API down: error + Reintentar.
9. Contratos de error de API (flujo)
| Caso | HTTP | UI |
|---|---|---|
| POST pedir, code inexistente | 404 | «Esa sesión no está.» |
| POST pedir, COMPLETA / remaining 0 | 409 | «No se puede pedir esa butaca.» |
| POST pedir, nombre vacío | 400 | «Escribe un nombre.» |
| POST pedir, red | — | oxblood + Reintentar; no navega a ok |
| GET mesa sin JWT | 401 | redirect login |
| Login malo | 401 | copy de login |
10. Dock en flujo
| Desde | Slot Pedir | Comportamiento |
|---|---|---|
/ sin contexto | Pedir | Scroll al primer ABIERTA o mensaje «Elige una noche» |
/sesion/BOB-2604 ABIERTA | Pedir | /pedir/BOB-2604 |
/sesion/BOB-2603 COMPLETA | Pedir | Disabled o mensaje completa |
/ok/:code | Cartelera | Vuelve 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:
| Entidad | Tabla SQL | Propósito |
|---|---|---|
| User | users | Identidad de oficio (rol PROGRAMADOR) |
| Session | sessions | Sesión JWT / token persistido |
| Sesión | sesiones | Noche programada (código BOB-XXXX, butacas, estado, cover) |
| Pedido | pedidos | Butaca 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
| Valor | Descripción |
|---|---|
PROGRAMADOR | Programadora de la mesa; único rol autenticado v1 |
SesionStatus
| Valor | Descripción |
|---|---|
ABIERTA | Quedan butacas (remaining > 0); se puede pedir |
COMPLETA | remaining = 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.namees el nombre de sala (oral), no una cuenta.
pedidos.notees texto libre opcional («voy con Inma»).
4. Tablas
users
| Columna | Tipo | Notas |
|---|---|---|
| id | BIGSERIAL PK | |
| TEXT UNIQUE | marta@bobina.cine | |
| password_hash | TEXT | bcrypt 12 · seed $2b$12$OEKcNck63neDJ.CrVP0lNOaXp2NG2zd2aMiGmnYY221h4ZAZ58x1m |
| name | TEXT | Marta Ruiz |
| role | TEXT | PROGRAMADOR |
| created_at | TIMESTAMPTZ |
sessions
| Columna | Tipo | Notas |
|---|---|---|
| id | UUID PK | sid del JWT |
| user_id | BIGINT FK | |
| expires_at | TIMESTAMPTZ | |
| revoked_at | TIMESTAMPTZ | logout |
| created_at | TIMESTAMPTZ |
sesiones
| Columna | Tipo | Notas |
|---|---|---|
| id | BIGSERIAL PK | |
| code | TEXT UNIQUE | BOB-2601 |
| title | TEXT | El espíritu de la colmena |
| director | TEXT | Víctor Erice |
| when_label | TEXT | jue 27 ago 20:00 (label humano; no timezone engine en v1) |
| seats | INTEGER | Capacidad total |
| remaining | INTEGER | Butacas libres |
| status | TEXT | ABIERTA | COMPLETA |
| cover | TEXT | /assets/sesiones/colmena.jpg |
| blurb | TEXT | Relato corto. Sesión ≠ estreno. |
| sort_order | INTEGER | 1 = primera del feed |
| created_at / updated_at | TIMESTAMPTZ |
pedidos
| Columna | Tipo | Notas |
|---|---|---|
| id | BIGSERIAL PK | |
| sesion_id | BIGINT FK | |
| code | TEXT | Denorm BOB-2604 para mesa sin join extra |
| name | TEXT | Nombre de sala (Luis Navarro) |
| note | TEXT NULL | Nota opcional |
| created_at | TIMESTAMPTZ |
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
| code | title | director | when_label | seats | remaining | status | cover |
|---|---|---|---|---|---|---|---|
| BOB-2601 | El espíritu de la colmena | Víctor Erice | jue 27 ago 20:00 | 12 | 12 | ABIERTA | /assets/sesiones/colmena.jpg |
| BOB-2602 | Los golfos | Carlos Saura | vie 28 ago 21:00 | 8 | 8 | ABIERTA | /assets/sesiones/golfos.jpg |
| BOB-2603 | Cría cuervos | Carlos Saura | sáb 29 ago 19:30 | 12 | 0 | COMPLETA | /assets/sesiones/cuervos.jpg |
| BOB-2604 | El sur | Víctor Erice | dom 30 ago 18:00 | 14 | 14 | ABIERTA | /assets/sesiones/sur.jpg |
| code | blurb (catálogo) | sort |
|---|---|---|
| BOB-2601 | Erice en la sala del barrio. Quedan butacas. No es Cinesa. | 1 |
| BOB-2602 | Saura a las 21:00. Calle y noche. Pedir butaca ≠ ticket. | 2 |
| BOB-2603 | Completa. Sin butacas. La bobina ya tiene dueños de asiento. | 3 |
| BOB-2604 | El 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
| Regla | Detalle |
|---|---|
| Unicidad de código | sesiones.code UNIQUE |
| Pedir solo ABIERTA | Si status ≠ ABIERTA o remaining ≤ 0 → 409 |
| Decremento atómico | UPDATE remaining = remaining - 1 WHERE remaining > 0; si 0 filas → 409 |
| Transición a COMPLETA | Tras update, si remaining = 0 → status = COMPLETA |
| Sin user en pedido | No FK a users desde pedidos |
| Mesa privada | GET /api/mesa exige JWT role PROGRAMADOR |
| Feed público | GET /api/sesiones sin auth |
8. Fuera del modelo v1
| Concepto | Por qué fuera |
|---|---|
| Precio / pago / QR | Pedir ≠ Cinesa |
| Email del vecino | Minimización; S2 |
| confirmada_at / north-star SQL | Analytics modelo; doc 12 |
Tabla ejemplares | Leftover LOMO |
Tabla programas | Leftover ONDA |
| Multi-tenant asociación | L1 compacto |
9. Naming vs leftover
| Prohibido (leftover) | Contrato BOBINA |
|---|---|
ejemplares | sesiones |
| BIBLIO | PROGRAMADOR |
lomo-api | bobina-api |
| LM-XXXX | BOB-XXXX |
| DISPONIBLE / EN_SALA / PEDIDO | ABIERTA / COMPLETA |
| sala (1–3) | when_label + seats/remaining |
06-tech-stack.md
06 — Stack técnico — BOBINA
1. Resumen
| Capa | Elección | Notas |
|---|---|---|
| Frontend | Angular (standalone) + Tailwind | Puerto 4200 |
| Backend | NestJS | Puerto 3026 · prefijo /api |
| DB | Neon PostgreSQL | Project tiny-feather-31905339 |
| Auth | JWT Bearer | Rol PROGRAMADOR |
| Package | pnpm | Apps independientes (pnpm --filter) |
| Diseño | Paper | File 01M0YE7DABVQNCPYK4JQPCSEEQ |
| Repo | /Users/cristian/orca/bobina-app | GH 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ón | Razón | Alternativa descartada |
|---|---|---|
| Angular standalone | Coherencia serie ALS-2 daily | Next/React (rompería espejo de cases) |
| NestJS | Mismo contrato API que LOMO/ONDA | Express suelto sin módulos |
| Neon | Postgres managed; project dedicado | SQLite local (no portfolio cloud) |
| Tailwind | Tokens candlelit rápidos | CSS modules sin design tokens |
| JWT | Mesa cerrada; feed abierto | Session cookie-only sin Bearer documentado |
| pnpm filter | Monorepo ligero sin npm workspaces | Turborepo pesado para L1 |
3. Puertos y health
| Servicio | Puerto | Health |
|---|---|---|
| API | 3026 | GET /api/health → { ok: true, service: "bobina-api" } |
| Web | 4200 | Angular 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 (/api → http://localhost:3026). [DECISIÓN]
5. Variables de entorno (API)
| Variable | Uso |
|---|---|
DATABASE_URL | Neon connection string (tiny-feather-31905339) |
JWT_SECRET | Firma HS256 |
PORT | 3026 |
NODE_ENV | development / production |
No commitear secretos. .env local; ejemplo en .env.example sin credenciales reales. [DECISIÓN]
6. Auth
| Pieza | Detalle |
|---|---|
| Login | POST /api/auth/login { email, password } |
| Hash | bcrypt 12 · seed fijo del encargo |
| Token | JWT · claims sub, email, role: PROGRAMADOR |
| Guard | Bearer en GET /api/mesa |
| Público | health, sesiones, sesiones/:code, POST pedir, login |
| Storage web | localStorage o memory + interceptor; logout limpia |
[COMPROBADO] Credenciales demo: marta@bobina.cine / password123.
7. Endpoints (contrato)
| Método | Ruta | Auth | Respuesta clave |
|---|---|---|---|
| GET | /api/health | No | bobina-api |
| GET | /api/sesiones | No | Array 4 |
| GET | /api/sesiones/:code | No | Relato |
| POST | /api/sesiones/:code/pedir | No | 201 / 409 / 404 / 400 |
| POST | /api/auth/login | No | { accessToken } |
| GET | /api/mesa | JWT | sesiones + pedidos |
CORS: origen http://localhost:4200 en dev. [DECISIÓN]
8. Frontend — rutas y componentes
| Ruta | Componente | Guard |
|---|---|---|
/ | CarteleraPage | — |
/sesion/:code | SesionPage | — |
/pedir/:code | PedirPage | — |
/ok/:code | OkPage | — |
/login | LoginPage | — |
/mesa | MesaPage | authGuard PROGRAMADOR |
Chrome: DockComponent (S-DOCK). Tokens Tailwind: ground, cream, card, brass, mute, oxblood.
9. Assets
| Origen case | Destino app |
|---|---|
2026-08-26-bobina/assets/hero.jpg | Cover / reference |
assets/sesiones/*.jpg | apps/web/public/assets/sesiones/ o equivalente |
Covers en DB como paths /assets/sesiones/colmena.jpg etc. [DECISIÓN]
10. Calidad y toolchains
| Herramienta | Uso v1 |
|---|---|
| TypeScript | Strict en api y web |
| ESLint / Prettier | Serie daily |
| Vitest / Jest | Smoke API opcional L1 |
| Playwright | Could; smoke manual en doc 13 |
11. Anti-stack (no introducir)
| Tecnología | Por qué no |
|---|---|
| Prisma obligatorio | Brief no lo exige; ensureSchema + pg válido |
| Stripe / pago | Pedir ≠ Cinesa |
| Firebase Auth | JWT propio PROGRAMADOR |
| GraphQL | REST L1 |
| Socket.io / chat | ≠ PREGÓN |
| Player video | ≠ Filmin |
| OPAC / Absys libs | ≠ LOMO |
12. Criterios de aceptación técnicos
GET /api/health→service: "bobina-api".- Seed idempotente: 1 PROGRAMADOR + 4 sesiones.
- POST pedir decrementa
remainingy puede pasar a COMPLETA. - GET mesa sin token → 401.
- Web en 4200 consume API 3026 sin mixed-content local.
- 0 referencias de producto a
ejemplares, BIBLIO,lomo-apien 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
| Eje | Sí | No |
|---|---|---|
| Superficie | Velvet #1A1210, cream #F4EDE4, card #241C18, brass #C4A574 | Caliza LOMO, cinta ONDA, hielo RAMAL, niebla PREGÓN |
| Tipo | Cormorant Garamond + Manrope | Source Serif+Outfit (LOMO), DM Serif+IBM Plex, Newsreader+Figtree |
| Foto | Still de sala a oscuras, butaca, haz de proyector, barrio | LED multiplex, marquee Times Square, stock Filmin |
| Grid | Pliego: still ≥40 % 16/10 + feed overlay de 4 noches | Hero 2-col + 3 cards (AP-12) · mesa de datos (LOMO) · galería 16/10 radio (ONDA) |
| Acento | Brass en CTA/foco/dock activo; oxblood en COMPLETA/error | Cobre mineral LOMO, cinta amarilla ONDA |
| Chrome | Dock Cartelera · Pedir · Mesa | Comando archivo, rail radio, split, kiosk |
3. Paleta
| Token | Hex | Rol |
|---|---|---|
| Ground / G-VELVET | #1A1210 | Terciopelo de butaca. Fondo de página. |
| Cream | #F4EDE4 | Texto primario, ficha legible sobre velvet. |
| Card | #241C18 | Asiento / tarjeta de sesión. Superficie elevada. |
| Brass | #C4A574 | Latón: CTA Pedir, foco, wordmark. Poco. |
| Mute | #8A7A6E | Meta, labels, noche secundaria, idle dock |
| Oxblood | #9A3B2F | Sello 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
| Uso | Familia | Tamaños de referencia |
|---|---|---|
| Wordmark | Cormorant Garamond 600 | 24–28 desktop · 22 mobile |
| Titular de cartelera / sesión | Cormorant Garamond 600 | 32–44 |
| Código BOB-XXXX | Cormorant Garamond 600 | 28–36 |
| Título de película | Cormorant Garamond 600 | 22–28 |
| Cuerpo / disclaimers | Manrope 400 | 16–17 / 26–28 lh |
| UI, dock, form, lista | Manrope 400/500/600 | 14 / 16 |
| Meta (noche, status, director) | Manrope 500 | 12–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 sí entran: el brief los fija. [COMPROBADO]
5. Fotografía
| Asset | Debe | No debe |
|---|---|---|
| hero.jpg | Still de sala a oscuras: velvet, haz, butaca, barrio | Marquee neón, multiplex, stock Filmin |
| colmena.jpg | Atmósfera de Colmena / Erice; grano, interior | Póster comercial con rating |
| golfos.jpg | Calle / noche Saura; cineclub | Cartel de estreno Cinesa |
| cuervos.jpg | Interior / infancia / sombra; COMPLETA se lee en UI | Play button overlay tipo VOD |
| sur.jpg | Luz de atardecer / umbral; ABIERTA | Trailer 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
| Mood | Por qué no |
|---|---|
| Neón / nocturnal multiplex | Primer instinto; es Cinesa |
| Mineral / caliza | Fue LOMO |
| Signage / cinta amarilla | Fue ONDA |
| Ice institucional | Fue RAMAL |
| Vehicle dashboard | Fue TEMPLE |
| Highlighter fog | Fue PREGÓN |
| Chapel amatista | Fue 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
| Gesto | Tratamiento |
|---|---|
| Entrada feed | Fade corto 120–160ms; still estático (no Ken Burns agresivo) |
| Hover tarjeta desktop | Ring brass 2px; sin lift excesivo |
| Dock activo | Brass en label/icono; idle mute |
| Reduced motion | 0ms; 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
| Token | Valor | Uso |
|---|---|---|
--ground | #1A1210 | Fondo de página (velvet) |
--cream | #F4EDE4 | Texto primario, títulos |
--card | #241C18 | Tarjeta de sesión, form, mesa |
--brass | #C4A574 | CTA, foco, dock activo |
--mute | #8A7A6E | Meta, idle |
--oxblood | #9A3B2F | COMPLETA, error |
--font-display | Cormorant Garamond | Titulares |
--font-sans | Manrope | UI |
--target | 44×44 min | Toques |
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)
| Par | Uso | Nota |
|---|---|---|
Cream #F4EDE4 sobre Velvet #1A1210 | Cuerpo y títulos | Debe pasar WCAG 2.2 AA |
Cream sobre Card #241C18 | Texto en tarjeta | Verificar AA |
| Brass sobre Velvet | Solo UI chrome / iconos, no párrafos largos | No sustituye cream |
| Mute sobre Velvet | Meta corta; no cuerpo | Evitar párrafos mute |
| Oxblood sobre Velvet | Sello COMPLETA + texto de error corto | Con 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
| Rol | Size / leading |
|---|---|
| Display cartelera | clamp(2.2rem, 5vw, 3.6rem) / 0.95 |
| H1 sesión / mesa | 2.5rem / 1 |
| H2 película | 28px / 32px |
| Cuerpo | 16–17 / 26 |
| Meta | 12–13 / 16, tracking 0.08em |
| Dock | 12–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
| Superficie | Grid |
|---|---|
| Cartelera 1440 | Still full-bleed; feed overlay 1 col o 2×2 de tarjetas; dock |
| Cartelera 390 | Still + stack de 4 tarjetas; dock fijo inferior |
| Sesión / Pedir / Ok / login | Columna max-w-lg (ok/login/pedir) · max-w-2xl (relato) |
| Mesa PROGRAMADOR | Lista + pedidos; stacked < lg |
Max page 1440px. Padding 20 / 40 / 48.
6. Estados de control
| Estado | Tratamiento |
|---|---|
| Default | Card + cream |
| Hover | Ring brass 2px |
| Focus visible | Outline brass 2px offset 2 |
| Active / pressed | Brass fill breve |
| Disabled | Opacity 0.45 · no hit · aria-disabled |
| Pending | disabled + aria-busy |
| Error | Borde 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
| Superficie | Tratamiento |
|---|---|
| Card sobre velvet | Sin sombra dura; borde 1px brass/10 o mute/20 |
| Dock | Elevación suave + blur; no material neón |
| Modal (si hubiera) | No en v1 Must |
9. Mapa a Paper UI
| UI | Componentes clave |
|---|---|
| UI-00 | Tokens |
| UI-01 / 02 | Still + tarjetas + dock |
| UI-03 / 04 | Relato |
| UI-05 | Form |
| UI-06 | Success |
| UI-07 | Login |
| UI-08 | Mesa |
| UI-09 | Empty |
| UI-10 | Error + Loading |
| UI-11 | Dock |
[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.
| Eje | Sí | No |
|---|---|---|
| Tono | Cálido, breve, de barrio | Corporativo multiplex, hype de estreno |
| Persona | «Pedimos butaca» / tuteo de sala | «Adquiere tu entrada» |
| Ritmo | Frases cortas. Una idea por línea en disclaimers | Párrafos legales de Filmin |
| Humor | Seco, poco | Memes, 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ón | Copy canónico |
|---|---|
| Butaca vs Cinesa | Pedir butaca ≠ entrada Cinesa. |
| Sesión vs estreno | Sesión ≠ estreno. |
| Cartelera vs Filmin | Cartelera ≠ Filmin. |
| Barrio vs centro | BOBINA no es los cines del centro. |
No se parafrasean hasta diluirlas. Pueden acortarse en UI estrecha manteniendo ≠. [DECISIÓN]
3. Glosario UI
| Concepto | Label canónico | Evitar |
|---|---|---|
| Home | Cartelera | Inicio, Hoy, Galería, Catálogo |
| Item | Sesión / Noche | Función, pase, screening, lomo |
| CTA | Pedir butaca | Comprar, Reservar entrada, Ver ahora |
| Success | Pedida | Confirmación de compra, Ticket listo |
| Staff | Mesa | Backoffice, Admin, Kanban |
| Estado | Abierta / Completa | Disponible / Agotado (retail), En sala (LOMO) |
| Persona auth | Programadora | Bibliotecaria, Conductora, Admin |
4. Pantalla a pantalla
Cartelera /
| Slot | Copy |
|---|---|
| Wordmark | BOBINA |
| Eslogan | La butaca, no la taquilla. |
| Empty | Aún no hay noches. |
| Error | La red no responde. · Reintentar |
Sesión /sesion/:code
| Slot | Copy |
|---|---|
| CTA ABIERTA | Pedir butaca |
| CTA COMPLETA | Completa. Sin butacas. |
| Meta | {director} · {when_label} · {remaining} butacas |
| Aviso | Pedir butaca ≠ entrada Cinesa. |
Pedir /pedir/:code
| Slot | Copy |
|---|---|
| Título | Pedir butaca |
| Label nombre | Tu nombre |
| Label note | Nota (opcional) |
| Placeholder note | Ej. Voy con Inma |
| Submit | Pedir butaca |
| Disclaimer | No es una entrada Cinesa. No hay pago. Sesión ≠ estreno. |
| Error nombre | Escribe un nombre. |
| Error 409 | No se puede pedir esa butaca. |
Success /ok/:code
| Slot | Copy |
|---|---|
| Titular | Pedida. |
| Código | {code} |
| Cuerpo | Butaca apuntada para {title} · {when_label}. |
| Oposiciones | Las cuatro líneas irrenunciables |
| Volver | Volver a la cartelera |
Login /login
| Slot | Copy |
|---|---|
| Título | Mesa |
| Ayuda | Solo programadora. |
| Demo | marta@bobina.cine |
| Error | Email o contraseña no valen. |
Mesa /mesa
| Slot | Copy |
|---|---|
| Título | Mesa |
| Empty pedidos | No hay pedidos. |
| Salir | Salir |
| Pie | Pedir butaca ≠ entrada Cinesa. |
5. Alt text de imágenes
| Asset | Alt (modelo) |
|---|---|
| hero | Sala de cineclub a oscuras, butacas de terciopelo, luz cálida |
| colmena | Still de sesión El espíritu de la colmena |
| golfos | Still de sesión Los golfos |
| cuervos | Still de sesión Cría cuervos |
| sur | Still 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
| Caso | Copy |
|---|---|
| Red | La red no responde. |
| 404 | Esa sesión no está. |
| 409 | No se puede pedir esa butaca. |
| 401 mesa | Entra como programadora. |
Sin culpa al usuario. Sin jerga HTTP en UI.
8. Anti-copy (vetado)
| Vetado | Por qué |
|---|---|
| Comprar entrada / ticket / QR | Cinesa |
| Ver ahora / Play / Mi lista | Filmin |
| Estreno / preestreno / taquilla | Circuito |
| Reservar 2 h / sala de ensayo | TEMPLE |
| Pedir mesa / lomo / signatura | LOMO |
| Pedir repetición / antena | ONDA |
| Recibido / En curso / Cerrado | PREGÓN kanban |
| «El 80% de vecinos…» | Estadística inventada |
9. Criterios de aceptación de contenido
- Las cuatro oposiciones aparecen al menos en success y en una superficie de cartelera o pedir.
- Ningún CTA dice Comprar / Play / Entrada.
- COMPLETA se etiqueta «Completa», no «Agotado» retail.
- Códigos se muestran como
BOB-XXXXen versales. - 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
| Par | Ratio objetivo | Uso |
|---|---|---|
#F4EDE4 sobre #1A1210 | ≥ 4.5:1 (texto) / ≥ 3:1 (UI grande) | Cuerpo, títulos |
#F4EDE4 sobre #241C18 | ≥ 4.5:1 | Texto en card |
#C4A574 sobre #1A1210 | ≥ 3:1 para UI no texto | Foco, iconos; no párrafos |
#8A7A6E sobre #1A1210 | Verificar; limitar a meta corta | Labels |
#9A3B2F + cream | Texto de error legible | Errores / 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
| Regla | Aplicación |
|---|---|
| Cuerpo ≥ 16px | Manrope 16–17 |
| Display no < 18px | Cormorant solo en titulares |
| Line-height ≥ 1.5 en cuerpo | 26–28 lh |
| Zoom 200% | Layout no rompe dock ni form |
| Sin justificado forzado | Alineación start |
4. Targets y pointer
| Elemento | Mínimo |
|---|---|
| Dock slots | 44×44 CSS px |
| CTA Pedir butaca | ≥ 44 px alto |
| Tarjeta de sesión | Hit area completa ≥ 44 alto |
| Inputs | ≥ 44 alto |
Spacing entre slots del dock ≥ 8px. [DECISIÓN]
5. Teclado y foco
| Superficie | Comportamiento |
|---|---|
| Cartelera | Tab por tarjetas → dock |
| Relato | Tab a CTA / atrás |
| Form | Nombre → note → submit |
| Login | Email → password → entrar |
| Mesa | Lista legible; salir alcanzable |
| Focus visible | Outline 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
| UI | Rol / nombre |
|---|---|
| Dock | navigation · aria-label «Dock BOBINA» |
| Slot activo | aria-current="page" |
| Tarjetas | link o article + enlace «{title}» |
| Status | Texto visible «Abierta» / «Completa» + no solo color |
| Form | label asociado; errores con aria-live="polite" |
| Loading | aria-busy="true" en región |
| Success código | Texto real, no solo imagen |
7. Imágenes y still
| Caso | Tratamiento |
|---|---|
| Still Pliego | alt descriptivo corto o alt="" si puro decorativo y el feed encima lleva el oficio |
| Covers sesión | Alt «Still de sesión {title}» |
| Iconos dock | aria-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
| Preferencia | Comportamiento |
|---|---|
prefers-reduced-motion: reduce | Transiciones 0ms; sin parallax del still |
| Default | 120–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).
/mesaredirige a login con foco en email.
11. Mobile 390
- Dock fijo no tapa el CTA final: padding-bottom ≥ altura dock.
- Formularios:
autocompletename on; passwordcurrent-password. - Viewport meta; sin zoom bloqueado. [DECISIÓN]
12. Criterios de aceptación a11y
- Cream sobre velvet usado en cuerpo; mute limitado a meta.
- Targets dock y CTA ≥ 44×44.
- Focus visible brass en todos los interactivos.
- Status con texto, no solo color.
- Reduced motion respetado.
- Form con labels y errores anunciables.
- 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
| Principio | Aplicación v1 |
|---|---|
| Minimización | Pedido = nombre + note opcional; sin email, teléfono, DNI |
| Separación público / oficio | Feed y POST pedir públicos; mesa JWT |
| Sin cuenta de vecino | Luis e Inma no se registran |
| Transparencia de copy | Success dice que no es compra Cinesa |
| Secretos fuera del repo | DATABASE_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
| Dato | Dónde | Base operativa (modelo) | Retención v1 |
|---|---|---|---|
| Nombre de pedido | pedidos.name | Prestación del cineclub (apuntar butaca) | Mientras el seed/demo viva; sin política de mercado afirmada |
| Note | pedidos.note | Opcional; texto libre del vecino | Igual |
| Email PROGRAMADOR | users.email | Cuenta de oficio | Cuenta demo |
| Password hash | users.password_hash | Auth | bcrypt 12 |
| JWT sid | sessions | Sesión de mesa | Expiració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
| Superficie | Público | Privado |
|---|---|---|
GET /api/sesiones | Sí · sin nombres de vecinos | — |
GET /api/sesiones/:code | Sí | — |
| POST pedir | Sí · crea pedido | — |
GET /api/mesa | No · 401 | Sí · pedidos con name |
| Feed UI | Sin listar quién pidió | — |
| Mesa UI | — | Lista pedidos |
[DECISIÓN] Enumerar vecinos en el feed rompería privacidad de sala; solo Marta ve nombres.
4. AuthN / AuthZ
| Control | Detalle |
|---|---|
| Password | bcrypt cost 12 · hash seed canónico del encargo |
| JWT | HS256 · secret env · role claim |
| Guard mesa | role === PROGRAMADOR |
| Login rate | Could L+1; v1 demo sin brute-force engine |
| Logout | Revoke session + clear client token |
| HTTPS | Obligatorio 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
| Amenaza | Mitigación |
|---|---|
| POST pedir spam | Capacidad remaining; Could rate-limit |
| Enumeración de pedidos | No en API pública |
| JWT robado | Expiración corta + logout; HTTPS en prod |
| IDOR mesa | Guard JWT; sin IDs de pedido públicos |
| XSS | Angular escaping; no innerHTML de note sin sanitize |
| SQLi | Parámetros prepared / query builder |
| Leftover ADMIN | Un 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 PII | Passwords, JWT completos |
| code de sesión en logs de pedido | Nombre completo en logs públicos |
9. Criterios de aceptación
- GET mesa sin Bearer → 401.
- GET sesiones no incluye
namede pedidos. - POST pedir no exige auth ni pago.
- Password solo como hash bcrypt.
.envno versionado con secretos reales.- 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
| Tipo | Métrica | Definición |
|---|---|---|
| North Star | % de noches ABIERTA con ≥1 pedido antes de las 18:00 | Oficio 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 descartada | Por qué no |
|---|---|
Pageviews de / | Vanidad; no mide butaca |
| Tiempo en Filmin-like | No hay VOD |
| Ingresos de taquilla | Pedir ≠ Cinesa; no hay pago |
| % reservas antes de las 11:00 | Eso 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étrica | Definición | Hipótesis |
|---|---|---|
| Activación vecino | 1.er POST /api/sesiones/:code/pedir exitoso por visitante | H1 |
| Tasa feed → relato | / → /sesion/:code | H1 |
| Tasa relato → pedir | /sesion → POST | H2 copy no frena |
| Rechazo COMPLETA | Visitas a BOB-2603 sin POST | Estado claro |
| Integridad auth | 401 en mesa sin token | Seguridad |
| Salud | 5xx rate API | Ops |
4. Eventos (contrato si se instrumenta L+1)
| Evento | Props | PII |
|---|---|---|
cartelera_view | — | No |
sesion_view | code, status | No |
pedir_submit | code | No nombre |
pedir_success | code | No |
pedir_conflict | code, http:409 | No |
login_success | role | No |
mesa_view | — | No |
[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
| Vetado | Por qué |
|---|---|
| Heatmaps de terceros sin decisión | Privacidad |
| Funnel de pago | No hay pago |
| DAU de Filmin | No hay VOD |
| Estadísticas de Vallecas inventadas | Ética de verdad |
8. Criterios de aceptación
- Docs y UI no muestran un % inventado como hecho.
- North star documentada y alineada al brief.
- Si hay eventos L+1, sin PII de pedidos.
- 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
| Entorno | URL | Notas |
|---|---|---|
| API local | http://localhost:3026 | Neon tiny-feather-31905339 |
| Web local | http://localhost:4200 | Proxy /api |
| Credenciales | marta@bobina.cine / password123 | Solo demo |
3. Smoke crítico (Must pasar)
| ID | Caso | Pasos | Esperado |
|---|---|---|---|
| S01 | Health | GET /api/health | ok · service: "bobina-api" |
| S02 | Feed | GET /api/sesiones · abrir / | 4 sesiones · Pliego visible |
| S03 | Relato ABIERTA | /sesion/BOB-2604 | El sur · 14 · CTA activo |
| S04 | Relato COMPLETA | /sesion/BOB-2603 | Cría cuervos · CTA disabled |
| S05 | Pedir | /pedir/BOB-2604 · nombre Luis · submit | 201 · /ok/BOB-2604 |
| S06 | Copy success | Leer /ok/BOB-2604 | 4 oposiciones visibles |
| S07 | 409 | Forzar pedir en BOB-2603 | 409 · mensaje butaca |
| S08 | Login | /login Marta | JWT · /mesa |
| S09 | Mesa auth | GET /api/mesa con token | 4 + pedidos |
| S10 | Mesa 401 | GET /api/mesa sin token | 401 |
| S11 | Mobile | / @390 | Dock · 4 noches · targets |
| S12 | Seed | Tras re-seed | 3 ABIERTA · 1 COMPLETA |
4. Regresión funcional
| ID | Área | Check |
|---|---|---|
| R01 | Decremento | Tras POST, remaining −1 |
| R02 | Autocomplete COMPLETA | remaining → 0 ⇒ status COMPLETA |
| R03 | Nombre vacío | 400 · no navega a ok |
| R04 | Code inventado | /sesion/BOB-9999 · 404 UI |
| R05 | Guard ruta | /mesa sin token → login ?next= |
| R06 | Logout | Token limpio · mesa 401 |
| R07 | Dock | Cartelera / Pedir / Mesa navegables |
| R08 | Note | Note opcional persiste en mesa |
| R09 | Público sin nombres | JSON sesiones sin name de pedidos |
| R10 | Leftover | 0 lomo-api / ejemplares / BIBLIO en UI |
5. Accesibilidad (muestra)
| ID | Check |
|---|---|
| A01 | Cream sobre velvet en cuerpo (inspección / contraste) |
| A02 | Focus visible brass en tab order |
| A03 | Dock slots ≥ 44×44 |
| A04 | Status con texto, no solo color |
| A05 | prefers-reduced-motion sin parallax |
| A06 | Labels en form pedir y login |
| A07 | aria-busy en loading feed |
6. Contenido
| ID | Check |
|---|---|
| C01 | Ningún CTA «Comprar» / «Play» / «Entrada» |
| C02 | Eslogan en cartelera |
| C03 | COMPLETA = «Completa» no «Agotado» retail |
| C04 | Códigos BOB-XXXX |
7. Visual / Paper
| ID | Check |
|---|---|
| V01 | Still a sangre + feed (no hero 2-col) |
| V02 | Mood candlelit (no neón multiplex) |
| V03 | Covers seed cargan (colmena/golfos/cuervos/sur) |
| V04 | Mesa = lista + pedidos (no kanban) |
8. API negativa
| Caso | HTTP |
|---|---|
| Login malo | 401 |
| Pedir sin nombre | 400 |
| Pedir COMPLETA | 409 |
| Pedir code 404 | 404 |
| Mesa sin auth | 401 |
9. Datos de prueba
| Actor | Dato |
|---|---|
| Vecino | Luis Navarro · note «Voy con Inma» |
| Sesión happy | BOB-2604 |
| Sesión bloqueo | BOB-2603 |
| PROGRAMADOR | marta@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
| Artefacto | Path |
|---|---|
| Brief | docs/00-day-brief.md |
| Paper ref | docs/00-paper-reference.md |
| Producto | docs/01-project-definition.md |
| IA / rutas | docs/03-information-architecture.md |
| Flujos | docs/04-user-flows.md |
| Datos | docs/05-data-model.md |
| Stack | docs/06-tech-stack.md |
| DS / tokens | docs/08-design-system.md |
| Copy | docs/09-content-guide.md |
| Build | docs/20-implementation.md |
| App | /Users/cristian/orca/bobina-app |
| Paper | 01M0YE7DABVQNCPYK4JQPCSEEQ |
| Neon | tiny-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 |
|---|---|
| 1 | Rutas / /sesion/:code /pedir/:code /ok/:code /login /mesa |
| 2 | Home = Pliego H-FEED (still + 4 noches), no H-DATA ni hero 2-col |
| 3 | Dock S-DOCK Cartelera · Pedir · Mesa |
| 4 | F-STORY: relato antes del form |
| 5 | POST pedir público; success con 4 oposiciones |
| 6 | JWT PROGRAMADOR; mesa 401 sin token |
| 7 | Seed 4 sesiones · 3 ABIERTA · 1 COMPLETA |
| 8 | Health bobina-api · puerto 3026 |
| 9 | Tokens candlelit + Cormorant/Manrope |
| 10 | Empty / error / loading |
| 11 | Mobile 390 usable |
| 12 | 0 dominio ejemplares / BIBLIO / lomo-api |
3. Mapa Paper → Angular
| UI | Ruta | Componente |
|---|---|---|
| UI-01 / 02 | / | CarteleraPage |
| UI-03 / 04 | /sesion/:code | SesionPage |
| UI-05 | /pedir/:code | PedirPage |
| UI-06 | /ok/:code | OkPage |
| UI-07 | /login | LoginPage |
| UI-08 | /mesa | MesaPage |
| UI-09 / 10 | estados | mismos components |
| UI-11 | chrome | DockComponent |
4. API checklist
| Método | Ruta | Auth |
|---|---|---|
| GET | /api/health | No |
| GET | /api/sesiones | No |
| GET | /api/sesiones/:code | No |
| POST | /api/sesiones/:code/pedir | No |
| POST | /api/auth/login | No |
| GET | /api/mesa | JWT PROGRAMADOR |
Body pedir: { name: string, note?: string }.
Decremento atómico de remaining. [DECISIÓN] ver doc 05.
5. Seed y credenciales
| Item | Valor |
|---|---|
marta@bobina.cine | |
| Password | password123 |
| Hash | $2b$12$OEKcNck63neDJ.CrVP0lNOaXp2NG2zd2aMiGmnYY221h4ZAZ58x1m |
| Codes | BOB-2601…2604 |
| Covers | /assets/sesiones/{colmena,golfos,cuervos,sur}.jpg |
6. Anti-patrones de implementación
| No hacer | Hacer |
|---|---|
| Puerto 3025 / health lomo-api | 3026 / bobina-api |
| Tabla ejemplares | sesiones |
Comando /buscar | Feed only |
| Kanban mesa | Lista + pedidos |
| Pago / Stripe | POST nombre |
| Player video | Relato estático |
| Hero 2-col marketing | Pliego foto-led |
7. Assets
Copiar desde case:
assets/sesiones/colmena.jpgassets/sesiones/golfos.jpgassets/sesiones/cuervos.jpgassets/sesiones/sur.jpgassets/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)
| Pregunta | Default |
|---|---|
¿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
| Fase | Nombre | Intención |
|---|---|---|
| L1 | Slice actual | Feed + relato + pedir + mesa JWT · cerrado en alcance |
| L+1 | Oficio cercano | Mejoras sin romper terna ni microcopy |
| L4 | Asociación real | Solo 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)
| Pieza | Estado |
|---|---|
| H-FEED Pliego 4 noches | Must |
| F-STORY relato | Must |
| Pedir butaca sin cuenta | Must |
| Success + 4 oposiciones | Must |
| Login PROGRAMADOR | Must |
| Mesa lista + pedidos | Must |
| Empty / error / loading / 390 | Must |
| Docs 00–20 + README + executive | Must |
| Paper 12 UX + 12 UI (inventario) | Must (ref) |
3. L+1 (Could cercano)
| ID | Idea | Valor | Riesgo |
|---|---|---|---|
| L1-01 | Rate-limit POST pedir | Anti-spam | Complejidad |
| L1-02 | Filtro mesa ABIERTA/COMPLETA | Oficio Marta | Scope creep UI |
| L1-03 | confirmada_at / vista north star interna | Métrica | No instrumentar PII |
| L1-04 | Ficha /mesa detalle pedido | Lectura | No kanban |
| L1-05 | Skip link + audit axe CI | A11y | — |
| L1-06 | Note maxlength + sanitize hard | Seguridad | — |
| L1-07 | Dock Pedir con deep-link inteligente | UX | No quinta sesión fantasma |
| L1-08 | Re-seed botón solo dev | Demo | No en prod |
Fuera de L+1: pago, Filmin, cuenta de vecino, chat, GPS.
4. L4 (explícitamente otro producto)
| Idea | Por qué L4 |
|---|---|
| Taquilla / precio / QR | Rompe «≠ Cinesa» |
| VOD / archivo streaming | Rompe «≠ Filmin» |
| Multi-sede / multi-programadora | Asociación real |
| App nativa + push | Plataforma nueva |
| RCPD completo + exportaciones | Legal de org real |
| Integración Filmoteca | Acuerdos reales |
| Proyeccionista / barra roles | S3 fuera |
5. Anti-roadmap (no disfrazar)
| Pedido típico | Respuesta |
|---|---|
| «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
| Dependencia | Nota |
|---|---|
Neon tiny-feather-31905339 | L1 |
| Paper file | Diseño; no bloquea docs |
| bobina-app rewrite | Paralelo a esta suite |
GH Criscode2022/bobina-app | Remoto |
7. Criterios para abrir L+1
- Smoke L1 en verde.
- Copy irrenunciable intacto.
- Ningún item L+1 introduce pago/VOD/chat.
- 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
| Token | Valor |
|---|---|
| Duración corta | 120–160ms |
| Easing | ease-out |
| Reduced motion | 0ms |
| Target | ≥44×44 |
| Pending | control 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
| Gesto | Resultado |
|---|---|
| Primera carga | Loading: skeleton still + 4 tiles card; aria-busy |
| 200 con 4 | Still a sangre + 4 tarjetas. Título, noche, butacas, estado |
| 200 con 0 | UI-09 empty «Aún no hay noches.» |
| Error 5xx / red | UI-10 + Reintentar (repite GET sesiones) |
| Tap tarjeta | /sesion/:code |
| Tap Mesa (dock) | /login o /mesa si hay token |
| Hover tarjeta desktop | Ring 2px brass. Sin lift excesivo |
| Tap Pedir (dock) sin contexto | Primer 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
| Gesto | Resultado |
|---|---|
| Primera carga | Loading: skeleton de relato |
| 200 ABIERTA | Cover, título, director, noche, remaining, blurb, copy × oposiciones, CTA |
| 200 COMPLETA | Igual + 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)
| Gesto | Resultado |
|---|---|
| Carga | Form + sesión en solo lectura + disclaimer |
| Nombre vacío + submit | «Escribe un nombre.» · no POST |
| Submit válido | POST · pending en botón |
| 201 | /ok/:code con state |
| 409 | oxblood + «No se puede pedir esa butaca.» |
| Red | seal + Reintentar; no navega a ok |
| Note | Opcional; no bloquea submit |
AC: no email, no DNI, no pago. Pedir butaca ≠ entrada Cinesa visible.
5. Success (UI-06)
| Gesto | Resultado |
|---|---|
| Entrada desde 201 | Código BOB-XXXX grande + título + noche + 4 oposiciones |
| Tap Volver | / |
| Deep link directo | Muestra sesión si GET ok; no inventa pedido |
AC: las cuatro oposiciones están. No QR. No «ticket listo».
6. Login (UI-07)
| Gesto | Resultado |
|---|---|
| Submit válido | POST login · guarda JWT · /mesa o next |
| 401 | «Email o contraseña no valen.» |
Guest en /mesa | Redirect /login?next=/mesa |
AC: sin signup. Ayuda demo mute.
7. Mesa PROGRAMADOR (UI-08)
| Gesto | Resultado |
|---|---|
| Primera carga | Loading skeletons lista + pedidos |
| 200 | 4 sesiones + pedidos (name, code, note, hora) |
| Empty pedidos | «No hay pedidos.» |
| 401 | Redirect login |
| Salir | Limpia token → / |
| Tap fila | Could 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
| Gesto | Resultado |
|---|---|
| Tap Cartelera | / |
| Tap Pedir | Contexto sesión ABIERTA → /pedir/:code; si no → prompt / primer ABIERTA |
| Tap Mesa | Auth → /mesa; guest → login |
| Activo | Brass + aria-current |
| Idle | Mute |
AC: tres slots. No hamburger. Targets ≥44px. Fijo en 390.
9. Empty / Error / Loading (UI-09 / UI-10)
| Estado | UI |
|---|---|
| Loading | Pulse card; aria-busy |
| Empty feed | Display + mute + sin CTA de Filmin |
| Empty mesa pedidos | Mute |
| Error | Titular + Reintentar brass |
10. Motion
| Gesto | Default | Reduced |
|---|---|---|
| Aparición feed | Fade 140ms | Instant |
| Hover ring | 120ms | Instant |
| Still | Estático | Estático |
Sin Ken Burns agresivo sobre el Pliego. [DECISIÓN]
11. Guión de interacción demo
/loading → 4 noches + still.- Hover/tap Cría cuervos → relato COMPLETA → CTA disabled.
- El sur → Pedir butaca → form Luis → pending → success.
- Dock Mesa → login → mesa con pedido.
- 390: dock no tapa CTA; scroll con padding.
12. Criterios de aceptación de interacción
- F-STORY no salta el relato.
- COMPLETA no permite POST.
- Pending no doble-envía.
- Dock siempre alcanzable en 390.
- Focus visible en todo el recorrido teclado.
17-prototype-map.md
17 — Mapa de prototipo — BOBINA
1. Fuentes
| Fuente | ID / path |
|---|---|
| Paper | https://app.paper.design/file/01M0YE7DABVQNCPYK4JQPCSEEQ |
| File ID | 01M0YE7DABVQNCPYK4JQPCSEEQ |
| UX-count | 12 |
| UI-count | 12 |
| App | /Users/cristian/orca/bobina-app |
| Case assets | 2026-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
| UX | Nombre | Doc espejo |
|---|---|---|
| UX-00 | Cover | README · executive · 07 |
| UX-01 | Stakeholders | 02 §3 |
| UX-02 | Personas | 02 §4 |
| UX-03 | JTBD | 02 §5 |
| UX-04 | Stories | 02 §6 |
| UX-05 | Journey | 02 §7 · 04 |
| UX-06 | Blueprint | 02 §8 |
| UX-07 | Site map | 03 |
| UX-08 | Flujos | 04 |
| UX-09 | Datos+permisos | 05 · 01 §5 · 11 |
| UX-10 | Métricas | 12 |
| UX-11 | Research | 02 |
3. UI producto → rutas / componentes
| UI | Nombre | Ruta | Componente Angular |
|---|---|---|---|
| UI-00 | Tokens | — (theme) | Tailwind config / styles |
| UI-01 | Cartelera feed | / | CarteleraPage |
| UI-02 | Cartelera mobile | / @390 | CarteleraPage |
| UI-03 | Sesión | /sesion/:code | SesionPage |
| UI-04 | Sesión mobile | /sesion/:code @390 | SesionPage |
| UI-05 | Pedir | /pedir/:code | PedirPage |
| UI-06 | Success | /ok/:code | OkPage |
| UI-07 | Login | /login | LoginPage |
| UI-08 | Mesa PROGRAMADOR | /mesa | MesaPage |
| UI-09 | Empty | mismas rutas | estados |
| UI-10 | Error+Loading | mismas rutas | estados |
| UI-11 | Dock | chrome global | DockComponent |
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
| Code | Título | Estado | Cover asset |
|---|---|---|---|
| BOB-2601 | El espíritu de la colmena | ABIERTA | sesiones/colmena.jpg |
| BOB-2602 | Los golfos | ABIERTA | sesiones/golfos.jpg |
| BOB-2603 | Cría cuervos | COMPLETA | sesiones/cuervos.jpg |
| BOB-2604 | El sur | ABIERTA | sesiones/sur.jpg |
Hotspots Paper deben usar estos códigos en labels si muestran URL. [DECISIÓN]
6. Breakpoints de artboard
| Artboard | Ancho ref |
|---|---|
| Desktop feed / sesión / mesa | ~1280–1440 |
| Mobile feed / sesión | 390 |
| Tokens / dock | según Paper |
7. Terna visible en prototipo
| Código | Evidencia en UI |
|---|---|
| R-IN | Velvet inmersivo + still a sangre |
| S-DOCK | UI-11 tres slots |
| H-FEED | UI-01 Pliego |
| F-STORY | UI-03 antes de UI-05 |
8. Gaps conscientes
| Gap | Notas |
|---|---|
| Paper no se regenera en esta pasada de docs | Inventario 00 intacto |
| Micro-interacciones pending | Spec en 16 |
| Analytics no en prototipo | Modelo 12 |
9. Criterios de aceptación del mapa
- Cada UI-00…11 tiene fila en esta tabla.
- Cada ruta Must tiene artboard.
- No hay artboard de
/buscar,/lomo, taquilla o player. - Mobile 390 cubierto (UI-02, UI-04).
18-completeness-audit.md
18 — Auditoría de cierre — BOBINA
1. Alcance L1
| Pieza | Estado |
|---|---|
| Docs 01–20 + README + executive | OK (este set) |
00-day-brief / 00-paper-reference | Intactos (no tocados) |
| Paper 12 UX + 12 UI | Inventario en 00 (no se arranca Paper aquí) |
App path /Users/cristian/orca/bobina-app | OK · rewrite en paralelo |
Neon tiny-feather-31905339 | OK |
API :3026 · health bobina-api | Contrato (leftover lomo-api prohibido) |
| Código sesiones + pedidos + JWT PROGRAMADOR | Contrato paralelo |
| Cierre sin deuda del L1 | OK · roadmap solo L+1 / L4 |
2. Terna y diversidad
| Check | Evidencia |
|---|---|
| R-IN · S-DOCK · H-FEED · F-STORY | Brief + 01 + 07 |
| 0 códigos = LOMO | LOMO era R-CL · S-CMD · H-DATA · F-LEAD |
| ≥2 vs ONDA / RAMAL | Dock/Feed/Story vs rail/gallery/search y split/full/onb |
| S-DOCK, H-FEED, F-STORY no en últimos 5 | Brief |
Ground G-VELVET #1A1210 | 00 + 07 + Tailwind |
| No leftover LOMO | 0 ejemplares / BIBLIO / comando en el contrato |
| Mood candlelit ≠ neón multiplex | 07 |
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
| AP | Mitigación |
|---|---|
| AP-12 hero 2-col | H-FEED Pliego still + feed |
| AP-21 card hueca | Título/noche/butacas/estado visibles |
| Leftover como estado | Contrato BOBINA; no se anota LOMO como producto vivo |
| Entrevistas inventadas | 02 etiquetado |
| ejemplares/BIBLIO/lomo-api | 0 en dominio; 05 + 20 |
| programas/CONDUCTOR/radio | 0 en dominio |
| H-DATA / S-CMD | Feed + dock; no mesa de datos ni comando |
| Estadísticas inventadas | Etiquetas [HIPÓTESIS]/[SUPUESTO] |
5. Seed
4 sesiones · 3 ABIERTA · 1 COMPLETA · Marta PROGRAMADOR · Luis sin cuenta · Inma fuera de login.
| code | title | status | remaining |
|---|---|---|---|
| BOB-2601 | El espíritu de la colmena | ABIERTA | 12 |
| BOB-2602 | Los golfos | ABIERTA | 8 |
| BOB-2603 | Cría cuervos | COMPLETA | 0 |
| BOB-2604 | El sur | ABIERTA | 14 |
6. Assets
| Archivo | Presente |
|---|---|
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
| Archivo | Estado |
|---|---|
| README.md | OK |
| presentation/executive-summary.md | OK |
| docs/01 … docs/20 | OK |
| 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
| Estado | Significado |
|---|---|
| Done (docs) | Definido y aceptado en la suite ALS |
| Must (build) | Obligatorio en el rewrite de bobina-app |
| Could L+1 | Opcional cercano sin romper terna |
| Won’t L1 | Fuera; ver roadmap L4 |
2. Épica A — Cartelera H-FEED
| ID | Ítem | Estado |
|---|---|---|
| A1 | Pliego still a sangre + feed 4 noches | Done docs · Must build |
| A2 | Tarjeta: título, director, when_label, remaining, status | Done docs · Must build |
| A3 | Tap → /sesion/:code | Done docs · Must build |
| A4 | Empty / loading / error | Done docs · Must build |
| A5 | Mobile 390 + assets covers | Done docs · Must build |
| A6 | Búsqueda comando /buscar | Won’t L1 (≠ LOMO) |
3. Épica B — Relato F-STORY
| ID | Ítem | Estado |
|---|---|---|
| B1 | /sesion/:code relato completo | Done docs · Must build |
| B2 | CTA Pedir butaca si ABIERTA | Done docs · Must build |
| B3 | CTA disabled si COMPLETA | Done docs · Must build |
| B4 | Copy irrenunciable en relato | Done docs · Must build |
| B5 | Player / trailer | Won’t L1 (≠ Filmin) |
4. Épica C — Pedir butaca
| ID | Ítem | Estado |
|---|---|---|
| C1 | /pedir/:code form name + note | Done docs · Must build |
| C2 | POST público 201 / 409 / 400 / 404 | Done docs · Must build |
| C3 | Decremento remaining + COMPLETA | Done docs · Must build |
| C4 | /ok/:code + 4 oposiciones | Done docs · Must build |
| C5 | Pago / QR / precio | Won’t L1 (≠ Cinesa) |
| C6 | Signup vecino | Won’t L1 (S2) |
5. Épica D — Mesa PROGRAMADOR
| ID | Ítem | Estado |
|---|---|---|
| D1 | Login JWT Marta | Done docs · Must build |
| D2 | /mesa lista + pedidos | Done docs · Must build |
| D3 | GET mesa 401 sin token | Done docs · Must build |
| D4 | Logout | Done docs · Must build |
| D5 | Kanban columnas | Won’t L1 (≠ PREGÓN) |
| D6 | Filtro estado / ficha pedido | Could L+1 |
6. Épica E — Chrome S-DOCK
| ID | Ítem | Estado |
|---|---|---|
| E1 | Dock Cartelera · Pedir · Mesa | Done docs · Must build |
| E2 | aria-current + targets 44 | Done docs · Must build |
| E3 | Pedir contextual | Done docs · Must build |
| E4 | Rail ONDA / comando LOMO | Won’t L1 |
7. Épica F — Design system & a11y
| ID | Ítem | Estado |
|---|---|---|
| F1 | Tokens velvet/cream/card/brass/mute/oxblood | Done docs · Must build |
| F2 | Cormorant + Manrope | Done docs · Must build |
| F3 | Contraste cream/velvet AA | Done docs · Must build |
| F4 | Reduced motion | Done docs · Must build |
| F5 | Modo letra grande Inma | Could L+1 |
8. Épica G — Plataforma
| ID | Ítem | Estado |
|---|---|---|
| G1 | Nest :3026 · health bobina-api | Done docs · Must build |
| G2 | Neon tiny-feather-31905339 schema+seed | Done docs · Must build |
| G3 | Angular rutas + guard | Done docs · Must build |
| G4 | pnpm apps independientes | Done docs · Must build |
| G5 | Instrumentación north star | Could L+1 |
| G6 | Multi-sede / Filmoteca | Won’t L1 · L4 |
9. Épica H — Documentación & diseño
| ID | Ítem | Estado |
|---|---|---|
| H1 | docs 00–20 + README + executive | Done |
| H2 | Paper UX 12 + UI 12 inventario | Done ref |
| H3 | Regenerar artboards Paper | Fuera de esta pasada docs |
10. Prioridad de build sugerida
- Schema + seed + health
- GET sesiones + CarteleraPage Pliego
- SesionPage + estados ABIERTA/COMPLETA
- POST pedir + OkPage copy
- Auth + MesaPage
- Dock + 390 + empty/error/loading
- Pulido tokens / a11y / smoke S01–S12
11. Contadores
| Tipo | Count (aprox) |
|---|---|
| Must build | ~35 |
| Could L+1 | ~8 |
| Won’t L1 | ~12 |
| Docs Done | Suite completa |
No se inventan story points ni velocidades de equipo. [DECISIÓN]
20-implementation.md
20 — Implementación — BOBINA
1. Resumen ejecutivo técnico
| Campo | Valor |
|---|---|
| App path | /Users/cristian/orca/bobina-app |
| GH | Criscode2022/bobina-app |
| API | NestJS · puerto 3026 · prefijo /api |
| Web | Angular standalone · puerto 4200 |
| Package | apps independientes (pnpm --filter) |
| DB | Neon PostgreSQL · project tiny-feather-31905339 |
| Tablas | users, sesiones, pedidos, sessions |
| Auth | JWT Bearer · role PROGRAMADOR (/mesa); feed y POST pedir públicos |
| Dominio | User, Sesión, Pedido |
| Fecha | 2026-08-26 |
| Health | bobina-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
| Rol | Password | |
|---|---|---|
| PROGRAMADOR | marta@bobina.cine | password123 |
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:
CREATE TABLEdeusers,sessions,sesiones,pedidos(doc 05).- Índices:
sesiones(code),sesiones(status),sesiones(sort_order),users(email),pedidos(sesion_id),pedidos(created_at DESC). - Seed idempotente:
- upsert PROGRAMADOR
marta@bobina.cine(hash bcrypt canónico) - upsert
sesionesporcode(BOB-2601…BOB-2604) restaurando status y remaining de catálogo - pedidos: no borrar pedidos de demo recientes salvo re-seed explícito
- upsert PROGRAMADOR
- Dominio: solo sesiones + pedidos + users. [DECISIÓN]
Upsert de sesiones por code sí 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)
| Tabla | Contenido |
|---|---|
users | PROGRAMADOR Marta |
sesiones | 4 noches |
pedidos | Butacas (las del POST) |
sessions | sid + 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)
| code | title | director | when_label | seats | remaining | status | cover |
|---|---|---|---|---|---|---|---|
| BOB-2601 | El espíritu de la colmena | Víctor Erice | jue 27 ago 20:00 | 12 | 12 | ABIERTA | /assets/sesiones/colmena.jpg |
| BOB-2602 | Los golfos | Carlos Saura | vie 28 ago 21:00 | 8 | 8 | ABIERTA | /assets/sesiones/golfos.jpg |
| BOB-2603 | Cría cuervos | Carlos Saura | sáb 29 ago 19:30 | 12 | 0 | COMPLETA | /assets/sesiones/cuervos.jpg |
| BOB-2604 | El sur | Víctor Erice | dom 30 ago 18:00 | 14 | 14 | ABIERTA | /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 === PROGRAMADORprotege/mesa. - Públicos: health, sesiones, sesiones/:code, POST pedir, login.
Oficio
| Método | Ruta | Auth | Notas |
|---|---|---|---|
| GET | /api/health | No | { ok: true, service: "bobina-api" } |
| GET | /api/sesiones | No | sort_order asc + remaining + status + cover |
| GET | /api/sesiones/:code | No | relato |
| POST | /api/sesiones/:code/pedir | No | INSERT pedido; remaining −1; COMPLETA si 0; 409 si no ABIERTA; 404 si no hay sesión |
| GET | /api/mesa | JWT | 4 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
| Path | Component | Guard |
|---|---|---|
'' | CarteleraPage | — |
sesion/:code | SesionPage | — |
pedir/:code | PedirPage | — |
ok/:code | OkPage | — |
login | LoginPage | — |
mesa | MesaPage | authGuard |
** | redirect '' | — |
Servicios
| Service | Responsabilidad |
|---|---|
SesionesApi | GET list/detail, POST pedir |
AuthApi | login, token store, logout |
MesaApi | GET mesa con Bearer |
DockState | slot activo / contexto pedir |
UI Must
CarteleraPage— still + feed overlay (Pliego), no tabla H-DATA.SesionPage— F-STORY.PedirPage— form.OkPage— código + 4 oposiciones.LoginPage/MesaPage.DockComponent— S-DOCK.- 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.jpggolfos.jpgcuervos.jpgsur.jpg
Paths en DB alineados a /assets/sesiones/.... [DECISIÓN]
7. Checklist anti-leftover
| Prohibido en runtime | Sustituto |
|---|---|
lomo-api | bobina-api |
| puerto 3025 | 3026 |
ejemplares | sesiones |
| BIBLIO | PROGRAMADOR |
| LM-XXXX | BOB-XXXX |
/buscar /lomo | / /sesion |
| DISPONIBLE/EN_SALA/PEDIDO | ABIERTA/COMPLETA |
| Source Serif / Outfit mineral | Cormorant / Manrope candlelit |
G-STONE #E4E0D6 | G-VELVET #1A1210 |
8. DoD técnico (merge)
- Smoke S01–S12 (doc 13) en verde.
- Health
bobina-api. - Seed idempotente.
- Mesa 401 sin token.
- Success muestra las 4 oposiciones.
- 390 + dock usable.
- 0 referencias de producto a ejemplares/BIBLIO/lomo-api.
- 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.