00-day-brief.md
00 — Day brief · 2026-08-25 · LOMO
Decisiones ALS-2 BRIEF
| Campo | Valor |
|---|---|
| Fecha | 2026-08-25 |
| Nombre | LOMO |
| Complejidad | Nivel 2 (no L1 consecutivo tras ONDA) |
| Sector | Archivo / biblioteca de barrio (sala de lectura, Usera) |
| Tipo | Mesa de ejemplares de hoy + comando de búsqueda + petición de reserva de sala + mesa BIBLIO JWT |
| Plataforma | Web responsive (mesa de datos en el mostrador · comando en el móvil) |
| Registro | R-CL — sala de lectura clásica, herramienta de datos |
| Shell | S-CMD — barra «buscar lomo o signatura» |
| Home | H-DATA — ejemplares de hoy (DISPONIBLE / EN_SALA / PEDIDO); lead métricas + tabla |
| Flujo | F-LEAD — pedir reserva de mesa; no es préstamo a casa |
| Por qué no ONDA | No S-RAIL / H-GALLERY / F-SEARCH; no radio; no cinta amarilla |
| Por qué no PIZARRA | Home no es catálogo search-first; es mesa de ocupación de hoy |
| Por qué no DERIVA | No mapa de paseos; el dato es el lomo en sala |
Terna unicidad
R-CL · S-CMD · H-DATA · F-LEAD
0 códigos iguales a N−1 (ONDA: R-HY · S-RAIL · H-GALLERY · F-SEARCH).
≥2 distintos vs N−2 (RAMAL) y N−3 (TEMPLE).
S-CMD, H-DATA y F-LEAD no están en los últimos 5.
Ground (CRON §5.6)
- Familia: G-STONE
- Hex:
#E4E0D6 - Por qué: polvo de caliza en la sala, no papel de cartel (ONDA), no hielo (RAMAL), no tinta de flight case (TEMPLE).
Mood visual (Paper)
- Candidatos: bookish/yeso (primer instinto biblioteca), mineral, chapel, alpine, fog
- Elegido: mineral — no el primer instinto librería cálida. Un lomo se lee bajo la caliza, con metal oxidado.
- Paleta:
#E4E0D6caliza (ground)#1C2B28tinta de lomo#FFFFFFficha#3E6B5Ecobre oxidado (mark)#5F6B67mute#9A5340sello (poco)
- Tipo: Source Serif 4 display · Outfit UI
Alcance L2 must
- Home datos: métricas de hoy + 4 ejemplares
- Comando de búsqueda (signatura / título)
- Ficha de lomo (sala, estado)
- Pedir reserva de mesa (pedir ≠ préstamo a casa)
- Login JWT BIBLIO
- Mesa de hoy (lista + pedidos)
- Empty / error / loading / mobile data
- ≥12 UX + ≥10 UI
Microcopy duro
- Reserva de sala ≠ préstamo a casa. No se lleva el libro.
- Lomo ≠ catálogo municipal. No sustituye a Absys ni al distrito.
- Pedir ≠ apuntarse al club. No inscribe al taller.
- LOMO no es la Biblioteca Regional.
Supuestos
- S1: La sala atiende 2–4 ejemplares/día en el slice; demo 4.
- S2: Rafa busca sin cuenta. JWT solo BIBLIO.
- S3: Nora (restauradora) fuera del producto.
- S4: Sin préstamo a domicilio, sin GPS, sin chat. [DECISIÓN]
Hipótesis
| ID | Señal |
|---|---|
| H1 | Una mesa de ocupación reduce colas en el mostrador |
| H2 | Separar reserva de sala de préstamo a casa evita el conflicto con el distrito |
| H3 | Cuatro lomos bastan; no hace falta el fondo completo |
00-paper-reference.md
Paper reference · LOMO
| URL | https://app.paper.design/file/01M0VVNT406AK640AK1ECY2DBR |
| File ID | 01M0VVNT406AK640AK1ECY2DBR |
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 Mesa datos · UI-02 Mesa mobile · UI-03 Comando · UI-04 Lomo · UI-05 Lomo mobile · UI-06 Pedir · UI-07 Success · UI-08 Login · UI-09 Mesa BIBLIO · UI-10 Empty · UI-11 Error+Loading
UX process (prefijo UX- · mínimo 12)
| ID | Nombre | Contenido |
|---|---|---|
| UX-00 | Cover | LOMO · «El lomo, no el prestado.» · R-CL · S-CMD · H-DATA · F-LEAD · L2 archivo · mineral · 2026-08-25 |
| UX-01 | Stakeholders | BIBLIO Inés, LECTOR Rafa, restauradora Nora fuera, distrito fuera |
| UX-02 | Personas | Inés Soto 47 · Rafa Díez 63 · Nora Ruiz 39 (docs) |
| UX-03 | JTBD | Job «saber si hay mesa para este lomo hoy sin hacer cola» |
| UX-04 | Stories | Must: datos, comando, ficha, pedir, login, mesa, estados |
| UX-05 | Journey | Mostrador → mesa de hoy → El río Manzanares → pedir mesa |
| UX-06 | Blueprint | Frontstage sala · backstage signatura/Neon/JWT |
| UX-07 | Site map | / datos · /buscar · /lomo/:code · /pedir/:code · /ok/:code · /login · /mesa |
| UX-08 | Flujos | F-LEAD público; mesa BIBLIO |
| UX-09 | Datos | User BIBLIO · Ejemplar; JWT en /mesa |
| UX-10 | Métricas | North star % de reservas de mesa confirmadas antes de las 11:00 |
| UX-11 | Research | Comprobado / supuesto / hipótesis / decisión |
UI producto (prefijo UI- · mínimo 10)
| ID | Nombre | Flujo |
|---|---|---|
| UI-00 | Tokens | DS mineral: limestone, copper oxide |
| UI-01 | Mesa datos | Split Deriva: rail de lomos + foto a sangre de la sala |
| UI-02 | Mesa mobile | 390 |
| UI-03 | Comando | Overlay buscar «manzanares» |
| UI-04 | Lomo | Ficha El río Manzanares sala 2 |
| UI-05 | Lomo mobile | 390 |
| UI-06 | Pedir | Form reserva de mesa |
| UI-07 | Success | Pedida. Reserva ≠ préstamo a casa |
| UI-08 | Login | JWT BIBLIO |
| UI-09 | Mesa BIBLIO | Lista + pedidos |
| UI-10 | Empty | Sin lomos |
| UI-11 | Error+Loading | Red / skeletons |
Mapeo Paper → Angular
| Artboard | Ruta | Componente |
|---|---|---|
| UI-01 Mesa datos | / | HoyPage |
| UI-03 Comando | /buscar | BuscarPage |
| UI-04 Lomo | /lomo/:code | LomoPage |
| UI-06 Pedir | /pedir/:code | PedirPage |
| UI-07 Success | /ok/:code | OkPage |
| UI-08 Login | /login | LoginPage |
| UI-09 Mesa | /mesa | MesaPage |
01-project-definition.md
01 — Definición de proyecto — LOMO
1. Identidad
| Campo | Valor |
|---|---|
| Nombre | LOMO |
| Significado | Lomo es el ejemplar que se lee en sala, no el libro que se lleva a casa ni el catálogo del distrito. Se entra a la mesa de ocupación; se sale habiendo pedido mesa. |
| Eslogan | «El lomo, no el prestado.» |
| Una frase | Mesa de ejemplares de hoy + comando de búsqueda + petición de reserva de sala + mesa BIBLIO JWT. |
| Sector | Archivo / biblioteca de barrio (sala de lectura, Usera) |
| Tipo | Web L2 — mesa H-DATA + comando S-CMD + lead F-LEAD + mesa JWT — Nivel 2, herramienta de ocupación usable |
| Plataforma | Web responsive (mesa de datos en el mostrador · comando en el móvil) |
| Mercado demo | España · Madrid · Usera (una sala de barrio, no la Biblioteca Regional) |
| Idioma | es-ES |
| Fecha caso | 2026-08-25 |
| Terna | R-CL · S-CMD · H-DATA · F-LEAD |
[COMPROBADO] Nombre, terna, nivel, sector, ground y paleta salen de docs/00-day-brief.md.
[SUPUESTO de catálogo] Usera / El río Manzanares / Planos de Usera es atrezzo de mercado, no el fondo de una biblioteca municipal real.
Tras ONDA (L1 radio, 2026-08-23) el día elige L2 archivo, no otro L1 consecutivo. N−1 es ONDA. [DECISIÓN]
2. Problema
Principal (hipótesis de diseño)
[HIPÓTESIS] El lector de Usera no necesita Absys ni la Biblioteca Regional: necesita saber si hay mesa para este lomo hoy sin hacer cola en el mostrador. Hoy eso vive en un cartel, una cola y una expectativa de préstamo a casa. La mesa de ocupación se lee como catálogo municipal; pedir mesa se lee como llevarse el libro; el producto se lee como la Regional. [SUPUESTO] Una sala atiende 2–4 ejemplares/día; no opera un préstamo a domicilio ni un club de lectura.
Secundarios
| Problema | Quién lo sufre | Efecto |
|---|---|---|
| «¿Está el Manzanares?» en cola | LECTOR (Rafa) | Espera, se va, no pide mesa |
| Pedir mesa se lee como préstamo a casa | LECTOR + Inés | Esperan un carnet y una fecha de devolución |
| La home se lee como catálogo del distrito | Rafa | Esperan talleres, Absys, sedes (eso fue PIZARRA) |
| Pedir se lee como apuntarse al club | Rafa + Inés | Esperan inscripción, lista de espera, plaza |
| La mesa BIBLIO se lee como kanban | BIBLIO (Inés) | Esperan Recibido / En curso / Cerrado |
| El dueño pide fondo completo y préstamo el día 1 | Sala | El L2 se vuelve Regional |
Supuestos (no investigación primaria propia)
- S1: La sala atiende 2–4 ejemplares/día en el slice; demo 4. [SUPUESTO]
- S2: Rafa busca sin cuenta. JWT solo BIBLIO. [SUPUESTO]
- S3: Nora (restauradora) fuera del producto. [SUPUESTO]
- S4: Sin préstamo a domicilio, sin GPS, sin chat. [DECISIÓN]
Hipótesis de producto
| ID | Hipótesis | Señal de validación (futura) |
|---|---|---|
| H1 | Una mesa de ocupación reduce colas en el mostrador | % de visitas a / que terminan en POST /pedir |
| H2 | Separar reserva de sala de préstamo a casa evita el conflicto con el distrito | ↓ «pensé que me lo llevaba»; copy visible en acuse |
| H3 | Cuatro lomos bastan; no hace falta el fondo completo | 0 OPAC; Inés decide el hoy sin Absys |
No se afirman estadísticas de bibliotecas inventadas. Todo lo anterior es razonamiento de diseño etiquetado.
3. Propuesta de valor
| Para | Valor |
|---|---|
| LECTOR (Rafa Díez) | Ve 4 ejemplares de hoy, busca «manzanares», abre El río Manzanares, pide mesa, se lleva el código. Nadie le pide cuenta ni carnet. |
| BIBLIO (Inés Soto) | Ve la mesa de hoy, lee estados y pedidos. No mueve columnas. No presta a casa. |
| RESTAURADORA (Nora Ruiz) | Fuera del slice de código. El oficio de conservación no entra en v1. |
| Sala LOMO | Una superficie mínima: ocupación + comando + mesa, sin préstamo y sin Regional. |
No es LOMO
| Excluido | Por qué |
|---|---|
| Préstamo a domicilio / carnet / devolución | Reserva de sala ≠ préstamo a casa |
| Catálogo municipal / Absys / OPAC | Lomo ≠ catálogo municipal |
| Club de lectura / inscripción / plaza | Pedir ≠ apuntarse al club |
| Biblioteca Regional / red de Madrid | LOMO no es la Biblioteca Regional |
| Fondo completo / miles de signaturas | H3 · S1 |
| Chat de lectores / 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) |
| Portada de nodos + checklist de alta | Eso fue RAMAL (H-FULL / F-ONB) |
| Home search-first de talleres | Eso fue PIZARRA (H-SEARCH); LOMO no es el distrito |
| Hero 2-col + 3 cards de «tu biblioteca» | Anti-patrón AP-12; contradice H-DATA |
| App de 40.000 ejemplares y CMS | L2 compacto, no OPAC regional |
4. Objetivos
Negocio / caso de estudio
- Demostrar vertical slice L2 archivo / biblioteca de barrio con Ejemplar + pedido + JWT BIBLIO.
- Portfolio coherente: Paper (12 UX + 12 UI) + docs + app runnable.
- Terna R-CL · S-CMD · H-DATA · F-LEAD frente a ONDA (rail/galería/archivo), RAMAL (split/portada/alta) y PIZARRA (search-first/distrito).
- No encadenar otro L1 tras ONDA. [DECISIÓN]
Usuario
| Rol | Objetivo medible en demo |
|---|---|
| LECTOR | Ver 4 filas, buscar «manzanares», pedir mesa de El río Manzanares y ver el acuse en < 90 s, sin cuenta |
| BIBLIO | Entrar a mesa, ver 4 ejemplares de hoy, leer LM-2501 y los pedidos en < 45 s |
| RESTAURADORA | No encuentra login; el oficio de conservación no está en la app |
No objetivos v1 (explícitos)
- Préstamo a domicilio, carnet, sanciones, devolución
- Catálogo municipal, Absys, OPAC, fondo completo
- Club de lectura, inscripción, lista de espera de taller
- Chat, kanban, columnas Recibido / En curso
- Cuenta de lector, socio, newsletter
- GPS, mapa de sedes, horario de la Regional
- Multi-sede, multi-bibliotecaria
- App nativa ni notificaciones push
- Rol RESTAURADORA autenticado
- 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 (lector) | BIBLIO | RESTAURADORA |
|---|---|---|---|
Ver mesa de datos / | Sí | Sí | No hay cuenta |
Buscar comando ?q= | Sí | Sí | — |
Ver ficha /lomo/:code | Sí | Sí | — |
Ver form /pedir/:code | Sí | Sí (no es el job) | — |
| POST pedir mesa | Sí | Sí (no es el job) | No |
Ver acuse /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) | — |
| Prestar a casa | No (no existe) | No | Fuera |
| Restaurar un documento | Copy: fuera | Copy: fuera | Oficio fuera de app |
[DECISIÓN] Un solo rol autenticado: BIBLIO. El lector no es un usuario del sistema: es autor/autora de un pedido. La restauradora 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 reservas de mesa confirmadas antes de las 11:00 | Oficio de sala, no pageviews |
| Activación lector | 1.er POST /pedir con code | H1 |
| Integridad de expectativa | Reclamaciones «¿me lo llevo?» / «¿es Absys?» / «¿me apunto al club?» | H2 + microcopy |
| Integridad de auth | GET /api/mesa sin token → 401; POST /api/ejemplares/:code/pedir sin token → 201 | Mesa pública de datos + mesa BIBLIO cerrada |
| Salud | Error rate API ejemplares / pedidos | 4xx/5xx |
7. Alcance funcional v1 (L2)
| Módulo | Incluido |
|---|---|
| Mesa de datos | GET /api/ejemplares · métricas de hoy + 4 filas |
| Comando | GET /api/ejemplares?q= · signatura / título, query «manzanares» |
| Ficha | GET /api/ejemplares/:code · título, sala, estado, cubierta |
| Pedir | POST /api/ejemplares/:code/pedir → acuse; reserva ≠ préstamo |
| Auth | POST /api/auth/login → JWT BIBLIO |
| Mesa BIBLIO | GET /api/mesa JWT · lista + pedidos, no kanban |
| Estados UI | Empty (0 lomos / 0 resultados), loading skeleton, error de red |
| Mobile | Mesa datos ~390px · filas apiladas · targets ≥44px |
| Seed | 1 BIBLIO, 4 ejemplares (2 DISPONIBLE, 1 EN_SALA, 1 PEDIDO) |
| Salud | GET /api/health → { ok: true, service: "lomo-api" } |
8. Criterios de aceptación de producto
/es la mesa de datos de hoy (métricas + 4 filas). No pide cuenta. No es un hero 2-col + 3 cards. No es una galería de cubiertas.- Un lector puede ver 4 ejemplares, tocar El río Manzanares, pedir mesa y obtener acuse en
/ok/LM-2501. /ok/:codedice explícitamente que reserva de sala no es préstamo a casa y que lomo no es catálogo municipal.- La UI dice explícitamente que LOMO no es la Biblioteca Regional y que pedir no es apuntarse al club.
- Sin token, GET
/api/mesaresponde 401. POST/api/ejemplares/:code/pediry GET/api/ejemplaresson públicos. - Un POST de pedir no crea user, no abre préstamo, no inscribe al club, no mueve kanban.
- Un BIBLIO inicia sesión y ve 4 ejemplares (2 DISPONIBLE, 1 EN_SALA, 1 PEDIDO) 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
lomos/*). - Chrome S-CMD: barra «buscar lomo o signatura». Mesa de datos sin top-nav de marketing y sin rail de radio.
- Rutas solo las del doc 03. No existen
/programa,/hoyJWT de ONDA,/nodos,/alta,/playlist,/prestamo. GET /api/healthdevuelveservice: "lomo-api"(noonda-api, noramal-api).- La mesa pública no muestra nombres de otros lectores; la mesa BIBLIO sí muestra pedidos con nombre.
/buscar?q=manzanaresdevuelve El río Manzanares.
9. Stack y artefactos
| Capa | Detalle |
|---|---|
| Frontend | Angular + Tailwind · puerto 4200 |
| Backend | NestJS · puerto 3025 |
| DB | Neon PostgreSQL · project dawn-butterfly-79519092 |
| Auth | JWT (BIBLIO) |
| Diseño | Paper 01M0VVNT406AK640AK1ECY2DBR |
| Repo app | /Users/cristian/orca/lomo-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 préstamo | «¿Me lo llevo a casa?» | Copy «Reserva de sala ≠ préstamo a casa» |
| Expectativa de catálogo | Absys, distrito, PIZARRA | Copy «Lomo ≠ catálogo municipal» |
| Expectativa de club | Inscripción, plaza, taller | Copy «Pedir ≠ apuntarse al club» |
| Expectativa de Regional | Red de Madrid, carnet único | Copy «LOMO no es la Biblioteca Regional» |
| Expectativa de kanban | Recibido / En curso | Lista + pedidos, no columnas de estado |
| Leftover ONDA | programas, CONDUCTOR, radio, onda-api | Contrato LOMO; health lomo-api; 0 copy de antena |
| Leftover RAMAL | nodes, altas, VOCAL, RM- | Dominio ejemplares + pedidos + BIBLIO |
| Fondo el día 1 | Alcance L4 disfrazado | H3: cuatro lomos |
| Cuenta de lector | Rompe S2 | Sin signup; POST público con nombre de mostrador |
| Home percibida como landing de biblioteca | Pérdida de H-DATA / AP-12 | Métricas + tabla; no hero 2-col |
| Home percibida como search-first | Confundir con PIZARRA | H-DATA; el comando no sustituye la mesa |
| Confundir con ONDA (galería + archivo) | Expectativa de cubierta / repetición | Mesa de ocupación; no cubiertas 16/10 de radio |
| Confundir con TEMPLE (kiosk + horas) | Expectativa de bloques de 2 h | Pedir mesa de un lomo; no slots |
| 0 ejemplares | Mesa vacía sin oficio | Empty «Aún no hay lomos hoy.» |
| Cola paralela en mostrador | H1 no se mide | North star etiquetada como modelo |
| Cobre oxidado como texto | Contraste WCAG | Mark pinta CTA/foco; ink escribe |
11. Glosario
| Término | Definición en LOMO |
|---|---|
| Lomo | Ejemplar físico en sala; el producto, no el prestado ni el OPAC |
| Ejemplar | Recurso (ejemplares); no es un título del catálogo municipal |
| Signatura | Código LM-XXXX; se busca en el comando |
| Sala | Espacio de lectura 1 / 2 / 3; no es préstamo a casa |
| Mesa (ocupación) | Superficie H-DATA pública de hoy; filas de ejemplares |
| Mesa (BIBLIO) | Superficie JWT de Inés (lista + pedidos, no kanban) |
| Pedido | POST 201; no significa préstamo ni club |
| Acuse | Código (LM-XXXX); no es un carnet |
| Disponible | Estado DISPONIBLE; se puede pedir mesa |
| En sala | Estado EN_SALA; alguien lo lee ahora |
| Pedido (estado) | Estado PEDIDO; ya hay mesa pedida |
| Comando | Chrome S-CMD: «buscar lomo o signatura» |
| BIBLIO | Usuario autenticado que opera la mesa |
| LECTOR | Autor/autora del pedido; no tiene fila en users |
| RESTAURADORA | Oficio de conservación; fuera del slice de código |
| Préstamo | Llevar el libro a casa; fuera |
| Absys / OPAC | Catálogo municipal; fuera. Lomo ≠ catálogo |
| Regional | Biblioteca Regional; fuera. LOMO no es la Regional |
| Mineral | Mood: caliza + cobre oxidado |
| Ground | Caliza #E4E0D6 |
| Ink | Tinta de lomo #1C2B28 |
| Card | Ficha #FFFFFF |
| Mark | Cobre oxidado #3E6B5E |
| Mute | #5F6B67 |
| Seal | Sello #9A5340, poco |
12. Decisiones de diseño (cierre de brief)
| ID | Decisión | Alternativa descartada |
|---|---|---|
| D1 | Home = mesa de datos (H-DATA) | Hero 2-col + 3 cards (AP-12) · galería (ONDA) · search-first (PIZARRA) · portada a sangre (RAMAL) |
| D2 | Shell comando «buscar lomo o signatura» (S-CMD) | Rail de radio · split mesa · dock · kiosk mínimo |
| D3 | Registro clásico de sala de lectura (R-CL) | Bookish/yeso (primer instinto biblioteca) · signage ONDA · ice RAMAL |
| D4 | Flujo F-LEAD (pedir reserva de mesa) | F-SEARCH como home, F-BOOK, F-KAN, F-ONB |
| D5 | Mood mineral | Bookish/yeso (primer instinto), chapel, alpine, fog, signage |
| D6 | Un rol autenticado BIBLIO | Multi-rol restauradora / lector / distrito |
| D7 | Status DISPONIBLE / EN_SALA / PEDIDO | Kanban de 3 columnas; «prestado»; «en club» |
| D8 | Lector sin cuenta | Signup, carnet, socio |
| D9 | Mesa pública no lista nombres de lectores | Tablero público enumerable |
| D10 | POST público de pedir con nombre de mostrador | Formulario de DNI + préstamo + club |
| D11 | Ground G-STONE #E4E0D6 | G-SIGN, G-ICE, G-INK, G-FOG, G-CHAPEL |
| D12 | Success de acuse en /ok/:code | Toast único sin pantalla |
| D13 | Búsqueda en comando /buscar, no como home | H-SEARCH tipo PIZARRA (rompería H-DATA) |
| D14 | Mesa BIBLIO = lista + pedidos, no kanban ni split | Recibido / En curso / Cerrado; lista | ficha RAMAL |
| D15 | Datos públicos + mesa JWT (no auth-first total) | Todo cerrado (rompería S2) · todo abierto (rompería mesa) |
| D16 | Sin préstamo a casa | Carnet + fecha de devolución |
| D17 | Leftover ONDA no es el producto | Mantener programas / CONDUCTOR / onda-api |
| D18 | Health lomo-api · puerto 3025 | leftover onda-api · :3023 |
13. Relación con el día anterior
| Case | Terna | Por qué LOMO no lo copia |
|---|---|---|
| ONDA (N−1) | R-HY · S-RAIL · H-GALLERY · F-SEARCH | No radio, no cubiertas, no repetición, no CONDUCTOR, no rail |
| RAMAL (N−2) | R-CL · S-SPLIT · H-FULL · F-ONB | No telecom, no nodos, no altas, no vocal, no split |
| TEMPLE (N−3) | R-HY · S-MIN · H-KIOSK · F-BOOK | No kiosk, no horas, no concierto; mesa ≠ coger sala de ensayo |
| PREGÓN (N−4) | R-IN · S-SIDE · H-CHAT · F-KAN | No admin pública, no chat, no kanban, no 112 |
| MATIZ (N−5) | R-HY · S-BOTTOM · H-BENTO · F-EDIT | No belleza, no PWA de oficio, no editor de gramos |
| PIZARRA | R-CL · S-CMD · H-SEARCH · F-SEARCH | Comparte S-CMD; no clona H-SEARCH ni el distrito. LOMO no es el distrito |
[COMPROBADO] El brief fija terna R-CL · S-CMD · H-DATA · F-LEAD. 0 códigos iguales a N−1 (ONDA). ≥2 distintos vs N−2 (RAMAL) y N−3 (TEMPLE). S-CMD, H-DATA y F-LEAD no están en los últimos 5. Ventana 4 días: R-HY (TEMPLE) + R-CL (RAMAL) + R-HY (ONDA) + R-CL. Ground G-STONE #E4E0D6, no G-SIGN ni G-ICE.
02-ux-research-strategy.md
02 — Estrategia de investigación UX — LOMO
Importante: este documento contiene artefactos de diseño y razonamiento secundario.
No hay entrevistas de campo primarias ni estadísticas inventadas presentadas como dato medido.
Etiquetas: [COMPROBADO] en producto, [SUPUESTO], [HIPÓTESIS], [DECISIÓN].
1. Objetivos de investigación (del caso)
| Objetivo | Método en este caso | Salida |
|---|---|---|
| Entender actores de la sala | Modelado de stakeholders + personas | §3–4 |
| Definir job de «saber si hay mesa para este lomo hoy sin hacer cola» | JTBD + stories Must | §5–6 |
| Mapear fricción cola / Absys / préstamo → mesa de ocupación | Journey + service blueprint | §7–8 |
| Traducir a requisitos L2 datos + comando + lead + mesa | Matriz hallazgo → requisito → feature | §9 |
2. Fuentes y límites
Fuentes admisibles (secundarias / operativas)
- Conocimiento general de archivos y salas de lectura de barrio (mostrador, signatura, ejemplar que no sale, restauradora que no entra el día 1, bibliotecaria que lee ocupación no un OPAC).
- Analogía operativa con superficie pública + panel JWT de la serie daily.
- Restricciones ALS-2: no préstamo a casa, no catálogo municipal, no club, no radio, no nodos/altas, no kiosk de horas.
Límites éticos de verdad
| Prohibido | Permitido |
|---|---|
| «El 58% de lectores de Usera hace cola para un lomo» sin fuente | «[SUPUESTO] Rafa abre la mesa de hoy desde el mostrador» |
| Citas de entrevistas ficticias como campo real | Quotes de persona etiquetadas como constructo de diseño |
| Volumen medido «17 reservas/semana del Manzanares» como KPI de mercado | Ejemplares de seed de producto, etiquetados como demo |
| Fondo oficial de una biblioteca de Usera 2026 | Ejemplares de seed; Inés, Rafa y Nora son personas de diseño |
| «Rafa existe y nos dijo…» | Rafa Díez es persona de diseño |
3. Stakeholders
| Stakeholder | Influencia | Interés | Necesidad principal |
|---|---|---|---|
| BIBLIO (Inés) | Alta | Muy alta | Ver el hoy y los pedidos sin kanban ni Absys |
| LECTOR (Rafa) | Alta en la reserva | Muy alta | Saber si hay mesa para este lomo hoy, sin cuenta |
| RESTAURADORA (Nora) | Media formal, baja en producto día 1 | Alta | Oficio de conservación; fuera del slice de código |
| Sala / archivo de barrio | Alta formal | Alta | Que se vea qué hay hoy; que no se confunda con la Regional ni con Absys |
| Biblioteca Regional / red de Madrid | Competencia / analogía falsa | — | Fuera de alcance; no clonar OPAC regional |
| Absys / catálogo municipal | Canal paralelo / analogía falsa | — | Fuera; Lomo ≠ catálogo municipal |
| Distrito / talleres PIZARRA | Analogía falsa de «apuntarse» | — | Fuera; pedir ≠ club |
| TEMPLE / local de ensayo | Analogía falsa de «reservar sala» de 2 h | — | Fuera; mesa de lomo ≠ slot de ensayo |
| ONDA / radio | Anti-patrón N−1 | — | Fuera; no programas, no CONDUCTOR, no antena |
| Grupo de WhatsApp del barrio | Canal paralelo | — | No es el backoffice |
Mapa de poder (resumen)
- Decisor de adopción: la sala (quién pone la mesa de hoy) y, en uso diario, Inés (quien mira pedidos).
- Usuario frecuente de pedir mesa: LECTOR (datos + comando + ficha + form, sin cuenta).
- Usuario frecuente de oficio: BIBLIO (mesa
/mesa). - Riesgo de rechazo: si el acuse parece un préstamo; si la fila parece un título de OPAC; si hay que crear cuenta; si la mesa parece un kanban; si el comando parece el buscador del distrito.
4. Personas
P1 — Inés Soto · BIBLIO
| Campo | Detalle |
|---|---|
| Edad / contexto | 47 años; lleva el mostrador en Usera; mesa de ocupación, no de Absys |
| Digital | Fluida en desktop de mesa; la mesa pública no es su herramienta principal, pero la mira |
| Goals | Ver qué está disponible, qué se lee en sala, qué se ha pedido |
| Pains | Cola a deshora; «¿me lo llevo a casa?»; un kanban que no es su oficio; un OPAC que no es su job de hoy |
| Quote de diseño | «Quiero ver el hoy. No un catálogo y no un préstamo.» |
| Email demo | ines@lomo.barrio / password123 |
Escenario: Entra a /login, abre /mesa, lee LM-2501 El río Manzanares DISPONIBLE, ve los pedidos. El copy dice que una reserva no es préstamo a casa.
[COMPROBADO] Nombre, edad, email demo y rol salen del encargo.
P2 — Rafa Díez · LECTOR
| Campo | Detalle |
|---|---|
| Edad / contexto | 63 años; vive en Usera; lee El río Manzanares cuando hay mesa; no quiere «otra cuenta de biblioteca» |
| Digital | Móvil desde la sala o el portal; no se hace socio si puede evitarlo |
| Goals | Ver si el Manzanares está disponible; buscarlo por signatura o título; pedir mesa; llevarse un código |
| Pains | La cola dice «creo que está en sala 2»; abre Absys; le venden un préstamo; cree que se apunta al club |
| Quote de diseño | «Solo quiero una mesa para este lomo. No me hagas un carnet.» |
Escenario: Abre / en el mostrador, ve la fila de El río Manzanares DISPONIBLE, o busca «manzanares» en el comando, toca la ficha, pide mesa, lee «reserva ≠ préstamo a casa» y el código LM-2501.
[COMPROBADO] Nombre, edad y gesto (lector, 63) salen del encargo. Es constructo de diseño, no entrevistado. [DECISIÓN]
Rafa no tiene fila en users. [DECISIÓN]
P3 — Nora Ruiz · RESTAURADORA (docs)
| Campo | Detalle |
|---|---|
| Edad / contexto | 39 años; restauradora de documentos; oficio de taller y papel, no de mostrador |
| Digital | No tiene login en el slice L2 |
| Goals | Conservar cuando la sala lo pida (fuera de app) |
| Pains | Que pedir mesa se lea como una orden de restauración; que la app le pida cuadrante |
| Quote de diseño | «La reserva no me programa. Yo no entro aquí.» |
[COMPROBADO] Nombre, edad y exclusión de login salen del encargo. [DECISIÓN] no hay cuenta RESTAURADORA en v1.
5. JTBD
Job principal (lector)
Cuando quiero saber si hay mesa para este lomo hoy, quiero ver la ocupación y pedir reserva de sala sin hacer cola, para dejar constancia en el mostrador sin que eso signifique préstamo, cuenta ni club.
Job principal (bibliotecaria)
Cuando hay ejemplares hoy y pedidos nuevos, quiero ver la lista de hoy y los pedidos, para mover el oficio de la sala sin un kanban ni un OPAC.
Jobs que LOMO no hace
| Job | Por qué no |
|---|---|
| Prestar a domicilio | Reserva de sala ≠ préstamo a casa · S4 |
| Consultar el catálogo municipal | Lomo ≠ catálogo municipal |
| Apuntarse a un club / taller | Pedir ≠ apuntarse al club |
| Sustituir a la Biblioteca Regional | LOMO no es la Biblioteca Regional |
| Coger hora de ensayo | ≠ TEMPLE |
| Pedir plaza de taller | ≠ PIZARRA |
| Pedir repetición de un programa | ≠ ONDA |
| Pedir nodo / alta de bloque | ≠ RAMAL |
6. Stories Must (v1)
| ID | Como | Quiero | Para |
|---|---|---|---|
| US-01 | Lector | Ver métricas de hoy + 4 filas | Distinguir ocupación de catálogo |
| US-02 | Lector | Buscar «manzanares» en el comando | Encontrar el lomo sin la cola |
| US-03 | Lector | Ver ficha (título, sala, estado) | Saber si está disponible, en sala o pedido |
| US-04 | Lector | Pedir mesa y ver acuse LM-XXXX | Dejar constancia, no llevarse el libro |
| US-05 | Bibliotecaria | Entrar con JWT | Abrir la mesa de pedidos |
| US-06 | Bibliotecaria | Ver lista de hoy + pedidos | Oficio sin kanban |
| US-07 | Ambos | Ver empty / error / loading | No quedarse en blanco |
Could (fuera de L2): login de Nora, préstamo, fondo completo, chat, cuenta de lector, Absys.
7. Journey (resumen)
- Rafa abre
/. Ve métricas (2 disponibles, 1 en sala, 1 pedido) y 4 filas. Lead El río Manzanares DISPONIBLE. [H1] - Toca El río Manzanares →
/lomo/LM-2501. (O busca «manzanares» en/buscar.) - Lee sala 2, estado Disponible. Copy irrenunciable.
- Toca Pedir mesa →
/pedir/LM-2501. Escribe su nombre. POST →/ok/LM-2501. Lee las cuatro oposiciones. - Inés entra a
/login→/mesa. Lista + pedidos. - Lee LM-2501 y el pedido de Rafa. Copy: reserva no es préstamo a casa.
Backstage: Nest + Neon + JWT. Nora no entra. El lomo no sale. No hay Absys.
8. Blueprint (resumen)
| Capa | Qué pasa |
|---|---|
| Frontstage (sala) | Mesa de datos en mostrador / móvil. Comando. Ficha. Form pedir. Acuse. |
| Backstage (archivo / taller) | Inés mira /mesa. Nora está en el taller, fuera de app. La signatura y el estante son oficio, no OPAC. |
| Soporte | Nest · Neon dawn-butterfly-79519092 · JWT BIBLIO · Paper mineral |
9. Matriz hallazgo → requisito → feature
| Hallazgo (etiquetado) | Requisito | Feature v1 |
|---|---|---|
| [HIPÓTESIS H1] Mesa de ocupación reduce cola | Métricas + 4 filas en fold | / H-DATA |
| [HIPÓTESIS H2] Reserva ≠ préstamo evita el distrito | Copy irrenunciable + POST que no crea préstamo | /pedir/:code + /ok/:code |
| [HIPÓTESIS H3] Cuatro lomos bastan | Sin fondo completo | Seed 4 · no OPAC |
| [SUPUESTO S2] Sin cuenta de lector | POST público + GET ?q= público | POST /api/ejemplares/:code/pedir |
| [SUPUESTO S3] Una bibliotecaria | Un rol JWT | BIBLIO |
| [DECISIÓN S4] Sin préstamo / GPS / chat | No carnet, no mapa, no hilo | Fuera de alcance |
10. Preguntas que este case no responde
- ¿Cuántas reservas reales hay en Usera en 2026?
- ¿Qué archivo opera El río Manzanares?
- ¿Rafa preferiría la cola?
- ¿Nora necesita un cuadrante de restauración?
- ¿Inés confirmaría la mesa antes de las 11: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.
Las personas son constructos. Usera / El río Manzanares / Planos de Usera son [SUPUESTO de catálogo].
ONDA no se investiga como producto vivo: es N−1; leftover programas / CONDUCTOR no es LOMO.
03-information-architecture.md
03 — Arquitectura de información — LOMO
1. Principios de IA
| Principio | Aplicación |
|---|---|
| Datos first | La home es métricas + 4 filas. No hay landing de marca por delante. No hay search como home |
| Público / mesa | Rafa pide mesa sin cuenta; Inés entra con JWT |
| Fila → ficha → form → acuse | Profundidad 3 desde la mesa de datos hasta el código (F-LEAD) |
| El lomo se busca en comando | S-CMD vive en la barra y en /buscar; no sustituye H-DATA |
| Mesa BIBLIO = lista + pedidos | Una columna + recuento; no kanban, no split lista | ficha |
| Lenguaje de dominio | Lomo, ejemplar, signatura, sala, pedido, mesa — no «track», «programa», «lead CRM», «préstamo» |
| Pedir no es prestar | El acuse no tiene fecha de devolución ni carnet |
| Lomo no es catálogo | No hay facetas de distrito, no hay Absys |
| Chrome de oficio | S-CMD «buscar lomo o signatura»; mesa de datos sin top-nav de marketing |
2. Sitemap
/ Mesa de datos pública (métricas + 4 filas) H-DATA
/buscar Comando · query + resultados S-CMD · público
/lomo/:code Ficha de lomo público
/pedir/:code Form reserva de mesa F-LEAD · público
/ok/:code Acuse post-pedido público
/login Login JWT BIBLIO público
/mesa Lista + pedidos auth
/** → redirect /
Árbol por audiencia
| Audiencia | Nodos relevantes |
|---|---|
| LECTOR | Hoy → (Buscar) → Lomo → Pedir → Ok. No ve /mesa |
| BIBLIO | Login → Mesa · (puede leer la mesa de datos y buscar) |
| RESTAURADORA | Ninguno como rol de sistema |
[COMPROBADO] Siete rutas del encargo L2. No se inventan /programa, /hoy (JWT ONDA), /nodos, /alta, /playlist, /prestamo, /club, /absys.
La búsqueda sí es ruta (/buscar): el comando se demuestra; la home sigue siendo datos. [DECISIÓN]
La ficha sí es ruta (/lomo/:code) porque el comando y la mesa necesitan URL compartible. [DECISIÓN]
El form sí es ruta (/pedir/:code): F-LEAD es un paso, no un POST oculto en la ficha. [DECISIÓN]
/ok/:code usa el código de ejemplar (LM-2501), no un código de petición distinto. L2 compacto. [DECISIÓN]
3. Navegación
Comando (S-CMD · todas las superficies salvo login/ok pueden mostrarlo)
| Slot | Destino | Visibilidad | Notas |
|---|---|---|---|
| Campo | /buscar?q= | Todos | Placeholder «buscar lomo o signatura». Overlay o página. |
| Wordmark LOMO | / | Todos | Vuelve a la mesa de datos. No es hero de marca |
| Mesa | /mesa | BIBLIO; si guest → /login?next=/mesa | Oficio JWT |
[DECISIÓN] El comando es la navegación primaria de hallazgo. La mesa de datos es la de ocupación. No hay rail Estudio / Buscar / Hoy (eso fue ONDA). No hay split (RAMAL), no dock, no kiosk mínimo (TEMPLE).
Desktop ≥960px: cabecera con wordmark + campo comando (~56px) + panel de datos.
El overlay de comando (UI-03) se abre al foco o al pulsar / · ⌘K. Submit navega a /buscar?q=. [DECISIÓN]
Mobile ~390px: campo de comando bajo el wordmark; la tabla se apila. [DECISIÓN] En 390 el comando no compite con un hamburger.
Mesa pública (H-DATA)
| Elemento | Destino | Notas |
|---|---|---|
| Wordmark LOMO | / | Sello mineral; no es hero 2-col |
| Eslogan | — | «El lomo, no el prestado.» |
| Métricas lead | — | Disponibles / En sala / Pedidos |
| Fila de ejemplar | /lomo/:code | 4 filas; signatura, título, sala, estado |
| Link Mesa (mute) | /login o /mesa si hay token | Secundario, no CTA de marca |
[DECISIÓN] La mesa de datos no tiene tabs de marketing, no tiene «Catálogo / Préstamo / Club». El comando basta para hallar.
Chrome de ficha y lead (F-LEAD)
| Slot | Destino | Notas |
|---|---|---|
| ← Hoy | / | Un paso atrás, no stepper de 5 |
| Campo query | /buscar?q= | GET ejemplares |
| Resultado | /lomo/:code | Misma ficha que la mesa |
| Pedir mesa | /pedir/:code | Form; no wizard 1—2—3 de fincas |
| Enviar | POST → /ok/:code | Una acción |
Chrome de mesa (/mesa autenticado)
| Slot | Destino | Visibilidad | Notas |
|---|---|---|---|
| Mesa | /mesa | Auth | Titular de oficio |
| Lista | — | Auth | Ejemplares de hoy |
| Pedidos | — | Auth | Nombre + signatura; no columnas |
| Hoy | / | Auth | Secundario vía wordmark |
| Salir | limpia token → / | Auth | Cabecera de mesa, no cuarto slot |
[DECISIÓN] No hay S-SPLIT (RAMAL). No hay kanban (PREGÓN). No hay /mesa/:code: L2 lee lista + pedidos. Could L+1: ficha de pedido.
4. Etiquetas de IA (UI)
| Concepto | Label |
|---|---|
| Home | Hoy / Mesa de hoy (no «Inicio», no «Catálogo», no «Galería») |
| Búsqueda | Buscar / Comando |
| Ficha | Lomo (no «programa», no «track», no «título SKU») |
| Form | Pedir mesa |
| Success | Pedida / código |
| Staff | Mesa (no «Backoffice», no «Hoy» tipo ONDA en UI JWT, no «Kanban») |
| Auth | Bibliotecaria (no «Área cliente», no «Conductora») |
| CTA | Pedir mesa (no «Prestar», no «Reservar 2 h», no «Inscribirse») |
En docs puede decirse «mesa de datos» para H-DATA y «mesa BIBLIO» para el oficio JWT. En UI pública el titular es Hoy. En UI autenticada el titular es Mesa. [DECISIÓN]
5. Contenido de cada nodo de IA
| Ruta | Qué hay | Qué no hay |
|---|---|---|
/ | Métricas, 4 filas, eslogan, comando | Cubiertas de radio, precios, login de lector, OPAC |
/buscar | Campo, query «manzanares», resultados, empty | Facetas municipales, chips de distrito |
/lomo/:code | Cubierta, título, sala, estado, copy, CTA | Préstamo, club, follow, player |
/pedir/:code | Nombre, ejemplar en solo lectura, disclaimer | DNI, email, carnet, socio |
/ok/:code | Código + 4 oposiciones | Contrato, préstamo, «ya está inscrito» |
/login | Email / clave BIBLIO | Signup de lector |
/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 métricas + 4 filas / resultados / lista de mesa |
| Empty hoy | «Aún no hay lomos hoy.» |
| Empty búsqueda | «Sin lomos.» |
| Empty mesa | «No hay pedidos.» |
| Error red | «La red no responde» + Reintentar |
| 404 lomo | «Ese lomo no está» en ficha |
7. Profundidad y búsqueda
La búsqueda sí es Must (S-CMD), pero no es la home (eso rompería H-DATA y copiaría PIZARRA). 4 ejemplares caben en la tabla; el comando se demuestra con q=manzanares → El río Manzanares. [DECISIÓN]
Inés no filtra la mesa en v1: ve el hoy entero + pedidos. Could L+1: filtro por estado.
Query: min 1 carácter tras submit o debounce; case-insensitive sobre title, code, lead. Vacío en /buscar sin q muestra prompt de comando, no los 4 (eso es la mesa de datos). [DECISIÓN]
8. Códigos y URLs
| Pieza | Forma |
|---|---|
| Ejemplar | LM-2501 … LM-2504 (LM versales, guion, 4 dígitos) |
| Ficha | /lomo/LM-2501 |
| Pedir | /pedir/LM-2501 |
| Acuse | /ok/LM-2501 |
| Búsqueda | /buscar?q=manzanares |
API puede normalizar lm-2501 → LM-2501. En UI siempre versales.
9. Lo que no entra en el mapa
/programa, /programa/:code, /hoy (JWT ONDA), /nodos, /alta, /mesa/:code, /playlist, /prestamo, /club, /inbox, /kanban.
Si el rewrite de lomo-app todavía tiene rutas ONDA (/programa, /hoy JWT, GalleryPage), no son el producto. Gana este doc.
04-user-flows.md
04 — Flujos de usuario — LOMO
1. Convenciones
| Token | Significado |
|---|---|
| F-LEAD | Pedir reserva de mesa; la home no es el form |
| Mesa | Lista BIBLIO, JWT |
| 201 | Pedido creado (pedida) |
| 409 | Ejemplar no DISPONIBLE |
| 401 | Mesa sin token |
| 404 | Lomo inexistente |
2. F1 — Lector pide mesa desde la ocupación (Must)
/ → GET /api/ejemplares
→ tap fila El río Manzanares → /lomo/LM-2501
→ GET /api/ejemplares/LM-2501
→ tap Pedir mesa → /pedir/LM-2501
→ escribe nombre «Rafa Díez»
→ POST /api/ejemplares/LM-2501/pedir { nombre }
→ 201 { code: LM-2501, title, status: PEDIDO, pedida: true }
→ /ok/LM-2501
Entrada: mesa de datos, sin cuenta.
Salida: código visible + copy «reserva de sala ≠ préstamo a casa».
Errores: red (reintentar), 404 lomo, 409 no disponible, 0 ejemplares (empty).
AC
- El form no pide email, DNI ni signup.
- POST no cobra, no crea user, no abre préstamo, no inscribe al club.
/ok/LM-2501muestra las cuatro oposiciones.- El paso
/pedir/:codeexiste: F-LEAD no es un POST oculto en la ficha. [DECISIÓN]
3. F2 — Lector busca en el comando (Must)
/buscar → escribe «manzanares» → GET /api/ejemplares?q=manzanares
→ resultados (El río Manzanares)
→ tap → /lomo/LM-2501
→ (sigue F1 desde la ficha)
Desde /, el foco en S-CMD abre overlay (UI-03) o navega a /buscar?q=. [DECISIÓN]
Entrada: comando, sin cuenta.
Salida: al menos El río Manzanares para q=manzanares.
Errores: q=zzzz → empty «Sin lomos.»; red → UI-11.
AC
- Home sigue siendo datos.
/buscarno redirige a/con un hero ni con H-SEARCH. - Query visible en el campo. Compartible
/buscar?q=manzanares. - Cero facetas de distrito / precio (eso fue PIZARRA).
- Cero archivo de programas (eso fue ONDA).
4. F3 — Bibliotecaria entra a mesa (Must)
/login → POST /api/auth/login
→ JWT BIBLIO
→ /mesa
→ GET /api/mesa
AC
- Sin token,
/mesaredirige a/login?next=/mesa. - GET
/api/mesasin Bearer → 401. - Lista de hoy: 4 filas + pedidos. No columnas Recibido / En curso.
- Desktop: lista + pedidos en el panel. 390: apilado bajo el comando.
5. F4 — Estados de sistema
| Estado | Trigger | UI |
|---|---|---|
| Loading hoy | GET ejemplares en vuelo | Skeletons de métricas + 4 filas |
| Empty hoy | 200 [] | «Aún no hay lomos hoy.» |
| Error hoy | 5xx / red | Reintentar |
| Loading buscar | GET ?q= en vuelo | Skeletons de resultado |
| Empty buscar | 200 [] | «Sin lomos.» |
| Loading ficha | GET :code | Skeleton de ficha |
| 404 ficha | código inexistente | «Ese lomo no está.» |
| Loading pedir | — | Form listo; submit pending |
| 409 pedir | EN_SALA o PEDIDO | «No se puede pedir esa mesa.» |
| 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 lector | S2 · Pedir ≠ club |
| Préstamo a casa | S4 · Reserva ≠ préstamo |
| Inscribirse al club | Pedir ≠ apuntarse al club |
| Chat | ≠ PREGÓN |
| Alta de nodo | ≠ RAMAL |
| Pedir repetición | ≠ ONDA |
| Wizard 1—2—3 de fincas | Pedir es un form corto, no onboarding |
| Login Nora | Slice L2 |
| PATCH estado de ejemplar | Inés lee; no mueve columnas en v1 |
| Fondo completo / Absys | H3 · S4 |
| Coger slot de 2 h | ≠ TEMPLE |
7. Tiempos de demo (modelo)
| Actor | Recorrido | Techo |
|---|---|---|
| Rafa | Hoy → Manzanares → pedir → pedida | < 90 s |
| Rafa (comando) | Buscar «manzanares» → ficha → pedir | < 90 s |
| Inés | Login → mesa → leer LM-2501 | < 45 s |
No son KPIs medidos. Son techos de diseño para el guión. [HIPÓTESIS]
8. Guión de demo canónico
/— métricas + 4 filas. Lead El río Manzanares DISPONIBLE. Eslogan. Comando.- Tap El río Manzanares — ficha DISPONIBLE · sala 2.
- Pedir mesa —
/pedir/LM-2501· nombre Rafa Díez. - Enviar —
/ok/LM-2501. Copy ×4. /buscar?q=manzanares— un resultado./login—ines@lomo.barrio/password123./mesa— lista + pedidos; LM-2501; pedido de Rafa si se hizo el POST.- 390: filas apiladas, no carousel; comando visible.
- API down: error + Reintentar.
9. Contratos de error de API (flujo)
| Caso | HTTP | UI |
|---|---|---|
| POST pedir, code inexistente | 404 | «Ese lomo no está.» |
| POST pedir, no DISPONIBLE | 409 | «No se puede pedir esa mesa.» |
| POST pedir, nombre vacío | 400 | «Escribe un nombre.» |
| POST pedir, red | — | seal + Reintentar; no navega a ok |
| GET mesa sin JWT | 401 | redirect login |
| Login malo | 401 | copy de login |
| Query vacía en buscar (sin submit) | no fetch | prompt de comando |
05-data-model.md
05 — Modelo de datos — LOMO
1. Visión general
Dominio L2 de mesa de ejemplares + comando + lead autenticable:
| Entidad | Tabla SQL | Propósito |
|---|---|---|
| User | users | Identidad de oficio (rol BIBLIO) |
| Session | sessions | Sesión JWT / token persistido |
| Ejemplar | ejemplares | Lomo de hoy (código LM-XXXX, sala, estado, cubierta) |
| Pedido | pedidos | Reserva de mesa anónima de cuenta sobre un ejemplar |
Base: PostgreSQL (Neon project dawn-butterfly-79519092) · IDs: serial + texto estable (LM-2501).
[DECISIÓN] ensureSchema es válido si el contrato de tablas se cumple; el brief de stack no exige Prisma.
Contrato de producto: ejemplares + pedidos + JWT BIBLIO.
No programas / repeticiones / nodes / altas / rooms / bookings.
2. Enums (aplicación; persistidos como TEXT + check)
Role
| Valor | Descripción |
|---|---|
BIBLIO | Bibliotecaria de la mesa; único rol autenticado v1 |
EjemplarStatus
| Valor | Descripción |
|---|---|
DISPONIBLE | En el estante; se puede pedir mesa |
EN_SALA | Alguien lo lee ahora; no es préstamo a casa |
PEDIDO | Ya hay mesa pedida; no es inscrito al club |
Pedir mesa solo está permitido en DISPONIBLE. EN_SALA y PEDIDO responden 409. [DECISIÓN]
3. Diagrama ER (texto)
users
id, email, password_hash, name, role(BIBLIO)
created_at
1 ──< sessions
sessions
id, user_id → users
expires_at, revoked_at
created_at
ejemplares
id
code (unique, LM-XXXX)
title, lead
status (DISPONIBLE|EN_SALA|PEDIDO)
sala (INTEGER 1–3)
cover
sort_order
created_at, updated_at
1 ──< pedidos
pedidos
id
ejemplar_id → ejemplares
nombre
created_at
v1: una sola BIBLIO opera sobre el conjunto global.
No hay FK de lector-usuario: el lector no se loguea.
pedidos.nombrees el nombre de mostrador (oral), no una cuenta.
4. Tablas
users
| Columna | Tipo | Notas |
|---|---|---|
| id | BIGSERIAL PK | |
| TEXT UNIQUE | ines@lomo.barrio | |
| password_hash | TEXT | bcrypt 12 · seed $2b$12$OEKcNck63neDJ.CrVP0lNOaXp2NG2zd2aMiGmnYY221h4ZAZ58x1m |
| name | TEXT | Inés Soto |
| role | TEXT | BIBLIO |
| 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 |
ejemplares
| Columna | Tipo | Notas |
|---|---|---|
| id | BIGSERIAL PK | |
| code | TEXT UNIQUE | LM-2501 |
| title | TEXT | El río Manzanares |
| lead | TEXT | Una frase. Reserva ≠ préstamo. |
| status | TEXT | DISPONIBLE | EN_SALA | PEDIDO |
| sala | INTEGER | 1 · 2 · 3 |
| cover | TEXT | /assets/lomos/estante.jpg |
| sort_order | INTEGER | 1 = lead de la tabla |
| created_at / updated_at | TIMESTAMPTZ |
pedidos
| Columna | Tipo | Notas |
|---|---|---|
| id | BIGSERIAL PK | |
| ejemplar_id | BIGINT FK | |
| nombre | TEXT | Nombre de mostrador (Rafa Díez) |
| created_at | TIMESTAMPTZ |
Sin email, sin teléfono, sin DNI, sin carnet. Pedir ≠ apuntarse al club. [DECISIÓN]
Índices: ejemplares(code), ejemplares(status), ejemplares(sort_order), users(email), pedidos(ejemplar_id), pedidos(created_at DESC).
Búsqueda q: ILIKE sobre title, code, lead. Trigram Could L+1; 4 filas no lo necesitan.
5. Seed
BIBLIO
ines@lomo.barrio / password123 · Inés Soto · BIBLIO
Hash bcrypt fijo: $2b$12$OEKcNck63neDJ.CrVP0lNOaXp2NG2zd2aMiGmnYY221h4ZAZ58x1m
Ejemplares
| code | title | status | sala | cover |
|---|---|---|---|---|
| LM-2501 | El río Manzanares | DISPONIBLE | 2 | /assets/lomos/estante.jpg |
| LM-2502 | Planos de Usera | EN_SALA | 1 | /assets/lomos/mesa.jpg |
| LM-2503 | Crónica del mercadillo | PEDIDO | 3 | /assets/lomos/silla.jpg |
| LM-2504 | Voces del barrio | DISPONIBLE | 2 | /assets/lomos/estante.jpg |
| code | lead (catálogo) | sort |
|---|---|---|
| LM-2501 | El río que corta Usera. Se lee en sala 2. No se lleva a casa. | 1 |
| LM-2502 | Planos del barrio. Ahora mismo en mesa de sala 1. | 2 |
| LM-2503 | Pregón escrito. Ya hay mesa pedida en sala 3. | 3 |
| LM-2504 | Voces del patio. Disponible en sala 2. | 4 |
[SUPUESTO de catálogo] Títulos, leads y salas son atrezzo. No es un fondo oficial.
Pedidos
Seed una fila: LM-2503 · nombre Carmen Vidal (constructo de mostrador, no cuenta).
El POST de smoke crea la de Rafa sobre LM-2501.
Inés puede ver 1 pedido al entrar en frío y ≥2 tras el guión.
El seed idempotente restaura los 4 estados de catálogo (2 DISPONIBLE, 1 EN_SALA, 1 PEDIDO) para que el demo sea repetible. [DECISIÓN]
6. JSON (camelCase)
API: sortOrder, createdAt, pedidoCount, cover, sala, status, title, code, lead, nombre.
SQL: sort_order, created_at, pedido_count derivado.
GET /api/ejemplares (item)
{
"code": "LM-2501",
"title": "El río Manzanares",
"lead": "El río que corta Usera. Se lee en sala 2. No se lleva a casa.",
"status": "DISPONIBLE",
"sala": 2,
"cover": "/assets/lomos/estante.jpg",
"sortOrder": 1
}
Lista pública: no incluye nombre de pedidos (evita enumerar lectores). [DECISIÓN]
Métricas de hoy (home puede derivarlas del array):
| Métrica | Seed |
|---|---|
| disponibles | 2 |
| enSala | 1 |
| pedidos | 1 |
| total | 4 |
GET /api/mesa (JWT)
{
"date": "2026-08-25",
"ejemplares": [{ code, title, status, sala, cover, pedidoCount, sortOrder }],
"pedidos": [{ code, title, nombre, createdAt, status }]
}
Orden ejemplares: DISPONIBLE, EN_SALA, PEDIDO, luego sort_order.
Orden pedidos: created_at DESC.
POST /api/ejemplares/:code/pedir → 201
Cuerpo:
{ "nombre": "Rafa Díez" }
Respuesta:
{
"code": "LM-2501",
"title": "El río Manzanares",
"sala": 2,
"status": "PEDIDO",
"pedida": true
}
Nombre obligatorio. No email. Si el ejemplar no está DISPONIBLE → 409. Si no existe → 404. Si nombre vacío → 400.
El POST pasa el ejemplar a PEDIDO. [DECISIÓN]
7. Generador de código
Los códigos de ejemplar son de catálogo, no se generan en el POST de pedir. Seed LM-2501…LM-2504. L+1 que añada ejemplares usa LM- + 4 dígitos correlativos; no es Must.
El acuse reutiliza el code del ejemplar. No hay LM-P-…. [DECISIÓN]
8. Qué no se modela
| Fuera | Motivo |
|---|---|
| Tabla restorers | Nora no entra |
| Tabla readers / socios / carnets | Pedir ≠ club · S2 |
| Tabla loans / due_at | Reserva ≠ préstamo · S4 |
| Tabla slots / rooms / bookings de 2 h | ≠ TEMPLE |
| programas / repeticiones | Dominio ONDA; no es el contrato |
| nodes / altas | Dominio RAMAL; no es el contrato |
| OPAC / fondo / absys | H3 · S4 |
06-tech-stack.md
06 — Stack tecnológico — LOMO
1. Visión
| Capa | Tecnología | Notas |
|---|---|---|
| Frontend | Angular standalone + signals | Puerto 4200 · web responsive |
| Estilos | Tailwind CSS | Tokens mineral (ground, ink, card, mark, mute, seal) |
| Backend | NestJS TypeScript | Puerto 3025, prefijo /api |
| Persistencia | PostgreSQL (ensureSchema) | Tablas users, ejemplares, pedidos, sessions |
| DB | Neon PostgreSQL | project dawn-butterfly-79519092 |
| Auth | JWT | Rol BIBLIO (/mesa); datos, comando y POST pedir públicos |
| Diseño | Paper | 01M0VVNT406AK640AK1ECY2DBR |
| Repo | /Users/cristian/orca/lomo-app/ | Rewrite en paralelo; este doc es el contrato |
| Package | pnpm | pnpm --filter · prohibido npm workspaces que rompen Angular (AP-06) |
Stack fijo del cron (D-P0-03). No React/Next/Firebase.
[COMPROBADO] Puerto 3025, Neon, Paper y path de app constan en el encargo.
El código se escribe en paralelo a esta suite. Si el repo todavía contiene leftover ONDA (programas, repeticiones, CONDUCTOR, onda-api, puerto 3023) o leftover RAMAL (nodes, altas, VOCAL), no es el estado del producto. Gana el contrato LOMO.
2. Estructura
lomo-app/
├── apps/api/ # Nest (paquete independiente)
├── apps/web/ # Angular + Tailwind (paquete independiente)
└── package.json # scripts api / start · apps independientes
D-P1-03: pnpm --filter. Prohibido npm workspaces que rompen Angular (AP-06).
Scripts raíz esperados:
| Script | Acción |
|---|---|
| api | Arranca Nest en :3025 |
| start / web | Arranca Angular en :4200 |
3. API pública vs JWT
| Método | Ruta | Auth |
|---|---|---|
| GET | /api/health | Público · { ok: true, service: "lomo-api" } |
| GET | /api/ejemplares | Público |
| GET | /api/ejemplares?q= | Público · comando |
| GET | /api/ejemplares/:code | Público |
| POST | /api/ejemplares/:code/pedir | Público |
| POST | /api/auth/login | Público |
| GET | /api/mesa | JWT BIBLIO |
CORS: origen http://localhost:4200 en local.
[COMPROBADO] Superficie de dominio del encargo: ejemplares, ?q=, :code, pedir, /mesa JWT. Health y login son el contrato de stack de la serie.
No se añaden Must extra (/programas, /repetir, /nodos, /altas, /prestamo).
Health: leftover onda-api → lomo-api. Puerto leftover de ONDA :3023 no se reutiliza: LOMO usa :3025. [DECISIÓN]
4. Justificación
| Elección | Razón |
|---|---|
| Angular + Nest | Alineación con la serie daily y el handoff del estudio |
| Neon serverless | Volumen bajo (S1: 2–4 ejemplares/día; demo 4 × pedidos de mostrador); no cola Redis |
| JWT BIBLIO | Mesa interna cerrada; la ocupación sí es pública |
Auth en servidor para /mesa | Source of truth = guard; el cliente no «esconde» pedidos |
| Puerto 3025 | Evitar colisión con ONDA :3023 / RAMAL :3022 / TEMPLE :3021 / PREGÓN :3020 |
| Web (no PWA Must) | S2: portal + mesa desktop; install Could L+1 |
code LM-XXXX | Acuse humano, no UUID en el mostrador |
| POST con nombre, sin email | Pedir ≠ apuntarse al club |
| pnpm | Encargo; filtro por app |
5. Variables
.env local (nunca git):
| Variable | Servicio | Descripción |
|---|---|---|
DATABASE_URL | API | Neon dawn-butterfly-79519092 |
JWT_SECRET | API | Firma tokens |
PORT | API | opcional, 3025 |
SESSION_TTL_SECONDS | API | opcional (default 86400) |
URI canónica (demo local, no commitear en frontend):
postgresql://neondb_owner:npg_GDsv4KLefP5d@ep-empty-star-a69kwo3y-pooler.us-west-2.aws.neon.tech/neondb?sslmode=require
Región: us-west-2 · pooler · sslmode=require.
.env.example solo placeholders.
Web: URL de API en ApiService (default http://localhost:3025/api). Proxy Angular proxy.conf.json → :3025.
6. Módulos API
health · auth · users · ejemplares · mesa · database · common.
Health: HealthService.name = 'lomo-api'.
main.ts PORT default 3025.
No módulos programas, hoy (JWT ONDA), repeticiones, nodes, altas. Si el rewrite los encuentra, se borran o se sustituyen. [DECISIÓN]
7. Frontend
Páginas: HoyPage / · BuscarPage /buscar · LomoPage /lomo/:code · PedirPage /pedir/:code · OkPage /ok/:code · LoginPage /login · MesaPage /mesa.
Guard JWT en /mesa. Interceptor Bearer. Token key lomo.accessToken.
8. Lo que el stack no es
No es Absys. No es la Biblioteca Regional. No es un OPAC. No es Prisma obligatorio.
No es un leftover de programas/repeticiones: el contrato es ejemplares + pedidos + BIBLIO.
No es un leftover de radio: health no dice onda-api.
07-creative-direction.md
07 — Dirección creativa — LOMO
1. Concepto
LOMO es una mesa de ocupación bajo caliza: se entra a cuatro filas y se sale habiendo pedido una mesa, no una landing de «tu biblioteca». El ground es polvo de caliza. El cobre oxidado puntúa, poco. El sello terracota marca pedido, poco.
Mood elegido: mineral.
Primer instinto descartado: bookish / yeso (librería cálida). Un lomo se lee bajo la caliza, con metal oxidado, no sobre papel de novela.
[COMPROBADO] Mood, ground y paleta salen de docs/00-day-brief.md.
2. Territorio visual
| Eje | Sí | No |
|---|---|---|
| Superficie | Caliza #E4E0D6, tinta #1C2B28, ficha #FFFFFF, cobre #3E6B5E | Papel de cartel ONDA, hielo RAMAL, ink TEMPLE, tiza PIZARRA |
| Tipo | Source Serif 4 + Outfit | DM Serif+IBM Plex, Newsreader+Figtree, Fraunces+Atkinson |
| Foto | Estante de sala, mesa de lectura, silla, archivo de barrio | Estantería de cadena, micro con cinta, mástil de operador, aula municipal |
| Grid | Mesa de datos: métricas + 4 filas; comando en cabecera | Hero 2-col + 3 cards (AP-12) · galería 16/10 (ONDA) · search-first (PIZARRA) |
| Acento | Mark #3E6B5E en CTA, foco, comando; seal #9A5340 en pedido | Cinta amarilla ONDA, cobre RAMAL, tiza PIZARRA |
| Chrome | Comando «buscar lomo o signatura» | Rail Estudio/Buscar/Hoy, split, dock, kiosk mínimo |
3. Paleta
| Token | Hex | Rol |
|---|---|---|
| Ground / G-STONE | #E4E0D6 | Polvo de caliza. Fondo de página. |
| Ink | #1C2B28 | Texto, wordmark, tinta de lomo. |
| Card | #FFFFFF | Ficha, fila, form. Superficie sobre caliza. |
| Mark | #3E6B5E | Cobre oxidado: CTA Pedir, foco, filete. Poco. |
| Mute | #5F6B67 | Meta, labels, sala secundaria, idle |
| Seal | #9A5340 | Sello «pedido» y error. Poco. No pinta el header. |
Jerarquía de color: la caliza carga; el cobre puntúa; el sello marca pedido. Si el mark pinta fondos enteros, deja de ser óxido y se vuelve «brand verde». El seal no decora la cabecera: solo puntual (PEDIDO, error). El texto sobre mark es card/blanco o ink según contraste; nunca mute. [DECISIÓN]
Candidatos de mood descartados: bookish/yeso (primer instinto biblioteca), chapel, alpine, fog.
4. Tipografía
| Uso | Familia | Tamaños de referencia |
|---|---|---|
| Wordmark | Source Serif 4 600 | 24–28 desktop · 22 mobile |
| Titular de hoy / mesa | Source Serif 4 600 | 32–44 |
| Código LM-XXXX | Source Serif 4 600 | 28–36 |
| Nombre de lomo | Source Serif 4 600 | 22–28 |
| Cuerpo / disclaimers | Outfit 400 | 16–17 / 26–28 lh |
| UI, comando, form, lista | Outfit 400/500/600 | 14 / 16 |
| Meta (sala, status, signatura) | Outfit 500 | 12–13, tracking 0.12em, ink o mute |
Prohibido: Source Serif 4 por debajo de 18px (se rompe). Outfit en el wordmark de hoy (se vuelve SaaS). Mark como color de texto de párrafo (contraste).
Fuentes vetadas de la serie reciente: DM Serif Display / IBM Plex Sans / Newsreader / Figtree / Fraunces / Atkinson Hyperlegible / Ibarra Real Nova / Jost / Libre Baskerville / Nunito / Instrument Serif / Sora / Cormorant / Public Sans / Spectral / Manrope / Zilla / Mulish / Lora / Karla.
Outfit sí entra: el brief lo fija para UI. No es el Outfit vetado de un cooldown antiguo frente a un brief explícito. [COMPROBADO]
5. Fotografía
| Asset | Debe | No debe |
|---|---|---|
| hero.jpg | Sala de archivo de barrio: caliza, estante, mesa, luz de Usera | Biblioteca Regional pulida, micro con cinta, aula de tiza |
| estante.jpg | Lomos en estante de sala; polvo, madera, signatura | Estantería IKEA de stock, cubiertas de radio |
| mesa.jpg | Mesa de lectura con planos / papel abierto | Mesa de mezclas, NOC, kiosk |
| silla.jpg | Silla de sala, ocupada o a punto; oficio de lectura | Silla de club, grada, butaca de concierto |
Alt: lomo + lugar, no «imagen1». Ver doc 09.
LM-2501 y LM-2504 comparten estante.jpg (disponibles). El lead y el título distinguen. [COMPROBADO] en seed.
6. Registro R-CL
Herramienta de datos de sala de lectura (clásica de archivo) + comando (oficio). No es un dashboard de seguros. No es un kiosk de horas. No es una galería de cubiertas. No es una librería cálida.
La innovación está en H-DATA + S-CMD + F-LEAD, no en un look «bookish». [DECISIÓN]
7. Anti-moods
| Mood | Por qué no |
|---|---|
| Bookish / yeso | Primer instinto; es librería cálida |
| Signage / cinta amarilla | Fue ONDA |
| Ice institucional | Fue RAMAL |
| Vehicle dashboard | Fue TEMPLE |
| Highlighter fog | Fue PREGÓN |
| Chapel amatista | Fue MATIZ |
| Tiza municipal | Fue PIZARRA |
8. Densidad (AP-21)
En el recorte de mesa de datos: eslogan + 3 métricas (disponibles / en sala / pedidos) + 4 filas con signatura, título, sala y estado visibles sin hover. Headline huérfano + foto = card hueca. [COMPROBADO] CRON §5.8.
08-design-system.md
08 — Sistema de diseño — LOMO
1. Tokens
| Token | Valor | Uso |
|---|---|---|
--ground | #E4E0D6 | Fondo de página (caliza) |
--ink | #1C2B28 | Texto |
--card | #FFFFFF | Ficha, fila, form |
--mark | #3E6B5E | CTA, foco, comando |
--mute | #5F6B67 | Meta |
--seal | #9A5340 | Pedido, error |
--font-display | Source Serif 4 | Titulares |
--font-sans | Outfit | UI |
--target | 44×44 min | Toques |
Tailwind: bg-ground, text-ink, bg-card, bg-mark, text-mute, text-seal, font-display.
La fila vive sobre --card; el ground es caliza alrededor. [DECISIÓN]
2. Escala de tipo
| Rol | Size / leading |
|---|---|
| Display hoy | clamp(2.2rem, 5vw, 3.6rem) / 0.95 |
| H1 mesa / ficha | 2.5rem / 1 |
| H2 lomo | 28px / 32px |
| Cuerpo | 16–17 / 26 |
| Meta | 12–13 / 16, tracking 0.12em, uppercase |
| Comando | 16 / 24, Outfit 400 |
3. Componentes
Fila de ejemplar (mesa de datos)
Thumb 4/3 recortado + signatura · título + sala + estado. Toda la fila es el hit. Destino /lomo/:code. Lead (El río Manzanares) ocupa la primera fila.
Métrica lead
Tres cifras: Disponibles · En sala · Pedidos. Número Source Serif, label Outfit mute. No gráficos.
Resultado de comando (buscar)
Misma anatomía en fila: thumb + título + sala + estado. Hit → ficha.
Overlay de comando (UI-03)
Campo a ancho de cabecera, resultados sobre card, query «manzanares». Esc cierra. Submit → /buscar?q=.
Ficha de lomo
Cubierta, título display, dl sala/estado/signatura, bloque de copy irrenunciable, CTA Pedir mesa (card sobre mark).
Form pedir
Nombre, ejemplar en solo lectura (código, título, sala), disclaimer, submit mark.
Acuse
Código Source Serif enorme + bloque card con título y sala + 4 oposiciones en mute.
Fila de mesa BIBLIO
Código · status · título · sala · recuento. Pedidos debajo: nombre · código · hora. Sin acciones PATCH en v1.
Login
Wordmark + dos inputs + CTA mark. Ayuda mute con demo.
Comando (S-CMD)
Campo «buscar lomo o signatura». Activo: filete mark 2px. Fondo card sobre ground.
Skeleton
animate-pulse bg-card. aria-busy.
Error
Titular display + cuerpo mute + Reintentar mark.
Sello PEDIDO / EN_SALA
Texto «Pedido» / «En sala» + seal o mute. Nunca solo el color. Poco: un sello por vista, no un header terracota.
4. Layouts
| Superficie | Grid |
|---|---|
| Hoy 1440 | Cabecera comando; métricas en 3 cols; tabla de 4 filas sobre card |
| Hoy 390 | Métricas en fila scroll-snap o wrap; filas apiladas |
| Buscar | Columna max-w-3xl |
| Lomo / Pedir / Ok / login | Columna max-w-lg (ok/login/pedir) · max-w-2xl (ficha) |
| Mesa BIBLIO | Lista + pedidos; stacked < lg |
Max page 1440px. Padding 20 / 40 / 48.
5. Estados de control
| Estado | Tratamiento |
|---|---|
| Default | Caliza, ink, card |
| Hover fila desktop | Ring 2px mark. Sin lift |
| Focus | Ring mark 2px |
| Disabled | opacity 50–60 |
| Error | Texto seal, no solo color |
| Activo (comando) | Filete mark |
| Pedida (CTA after 201) | Navega a ok; no deja el botón en «Prestar» |
6. Iconografía
Cero iconos decorativos de «libro abierto / carnet / antena / play». El oficio es tipográfico + foto + cobre. Comando: lupa mínima, stroke ink, 20px, no pack de color. [DECISIÓN]
7. Motion
120–160ms ease-out. Reduced motion: 0ms. Skeletons pulse; no spinners de Regional ni de radio.
8. Densidad (AP-21)
En el recorte de mesa: eslogan + 3 métricas + 4 filas con signatura, título, sala y estado. [COMPROBADO] CRON §5.8.
9. Contraste de cobre
#3E6B5E sobre #E4E0D6 no es texto de párrafo. CTA = text-card o text-ink sobre bg-mark según ratio ≥ 4.5:1. Meta = mute o ink sobre ground/card. Seal sobre ground ≥ 4.5:1 para el rótulo «Pedido» (el sello lleva texto, no solo círculo).
09-content-guide.md
09 — Guía de contenido — LOMO
1. Voz
Cercana de mostrador y de sala. Tuteo en UI al lector. Segunda persona cuando la interfaz habla. Tercera cuando habla el hoy (El río Manzanares ocupa…).
Sin jerga de Regional («tu carnet único», «red de Madrid», «préstamo interbibliotecario»). Sin Absys. Sin «apúntate al club». Sin sirena. Sin kanban en UI. Sin antena ni repetición.
El producto se mira y se pide mesa. No vende préstamo, no es la Regional, no inscribe al club, no crea cuenta.
2. Palabras permitidas / prohibidas
| Usar | No usar |
|---|---|
| Lomo / ejemplar / signatura | Programa, track, título SKU, OPAC |
| Pedir mesa | Prestar, llevarse a casa, inscribirse, play |
| Disponible / en sala / pedido | Recibido, En curso, Prestado, En antena |
| Hoy (público) / Mesa (BIBLIO) | Kanban, backoffice, catálogo, galería |
| Bibliotecaria | Conductora, vocal, coordinadora de distrito, tutor |
| Lector | Cliente, lead, socio, oyente |
| Sala | Reserva de 2 h, TEMPLE, slot, estudio de radio |
| LOMO no es la Biblioteca Regional | Red de Madrid, Absys, carnet único |
| Reserva de sala ≠ préstamo a casa | Devolución, sanción, renovación |
«Kanban», «F-LEAD» y «H-DATA» son lenguaje de diseño, no de UI: Rafa no lee «lead pattern»; Inés lee Disponible / En sala / Pedido.
«Mesa» en UI autenticada es el oficio. En pública el titular es Hoy. Si hay ambigüedad en ficha, CTA = Pedir mesa, nunca «Reservar sala de 2 h». [DECISIÓN]
3. Microcopy duro (literales irrenunciables)
El brief fija oposiciones. Aparecen donde el usuario puede confundirse.
| Oposición | Dónde | Copy |
|---|---|---|
| Reserva de sala ≠ préstamo a casa | Ficha · pedir · acuse · pie de mesa | «Pedir mesa no es un préstamo. El lomo no se lleva a casa.» |
| Lomo ≠ catálogo municipal | Hoy · buscar · acuse | «Esto no es el catálogo del distrito. Es la ocupación de hoy.» |
| Pedir ≠ apuntarse al club | Ficha · pedir · acuse | «Pedir mesa no te apunta a ningún club.» |
| LOMO no es la Biblioteca Regional | Hoy · acuse | «LOMO no es la Biblioteca Regional. Es la sala del barrio.» |
[DECISIÓN] Los cuatro textos son obligatorios en UI. No se diluyen a un tooltip.
Pie de hoy puede condensar dos en dos líneas; acuse muestra los cuatro.
4. Microcopy por superficie
| Superficie | Copy |
|---|---|
| Eslogan | El lomo, no el prestado. |
| Línea de lugar | Usera |
| Hoy titular | Hoy |
| Métrica 1 | Disponibles |
| Métrica 2 | En sala |
| Métrica 3 | Pedidos |
| Comando placeholder | buscar lomo o signatura |
| Buscar titular | Comando |
| Buscar submit | Buscar |
| Ficha volver | ← Hoy |
| Ficha CTA | Pedir mesa |
| Pedir titular | Pedir mesa |
| Pedir nombre | Nombre |
| Pedir submit | Pedir mesa |
| Pedir ayuda | Solo un nombre de mostrador. No es un carnet. |
| Login titular | Entrar a la mesa |
| Login ayuda | Solo bibliotecaria. El lector pide mesa en el hoy, sin cuenta. |
| Login submit | Entrar |
| Login error | Email o contraseña no valen. |
| Empty hoy | Aún no hay lomos hoy. |
| Empty buscar | Sin lomos. |
| Empty mesa | No hay pedidos. |
| Success titular | Pedida. |
| Success código | LM-2501 |
| Success cuerpo | Pedir mesa no es un préstamo. El lomo no se lleva a casa. |
| Success extra | LOMO no es la Biblioteca Regional. Pedir no te apunta al club. Esto no es el catálogo municipal. |
| Success CTA | Volver al hoy |
| Error | La red no responde. |
| Error retry | Reintentar |
| Loading | Cargando |
| 404 lomo | Ese lomo no está. |
| 409 pedir | No se puede pedir esa mesa. |
| Mesa titular | Mesa |
| Salir | Salir |
| Link Mesa (hoy) | Mesa |
| Status DISPONIBLE | Disponible |
| Status EN_SALA | En sala |
| Status PEDIDO | Pedido |
| Sala | Sala 1 / Sala 2 / Sala 3 |
5. Ejemplares seed (tono)
Los ejemplares demo se escriben como lomos de sala de barrio, no como ficha de OPAC ni como anuncio de club.
| Pieza | Tono |
|---|---|
| El río Manzanares | Estante. Sala 2. Disponible. No se lleva. |
| Planos de Usera | Mesa. Sala 1. En sala. Papel abierto. |
| Crónica del mercadillo | Silla. Sala 3. Pedido. Pregón escrito. |
| Voces del barrio | Estante. Sala 2. Disponible. Patio. |
No inventar declaraciones de lectores reales. Si hay una voz, es de persona de diseño etiquetada.
En EN_SALA no se reescribe a «prestado hasta el 12». El cierre es el estado. [DECISIÓN]
6. Nombres propios del seed
| Nombre | Uso |
|---|---|
| Inés Soto | BIBLIO; ines@lomo.barrio |
| Rafa Díez | LECTOR; sin cuenta; pide El río Manzanares |
| Nora Ruiz | RESTAURADORA; sin cuenta; (fuera) |
| Carmen Vidal | Nombre de mostrador del pedido seed de LM-2503; no es cuenta |
| LOMO · Usera | Sala demo; El río Manzanares / Planos de Usera |
No inventar CIF de biblioteca, código de sede municipal, ni Absys real como si fuera el producto. [SUPUESTO de catálogo demo]
Usera es topónimo reconocible, no un inventario oficial de una biblioteca 2026.
No usar Nerea, Iker, Pilar, Patio 17, CONDUCTOR, programas. [DECISIÓN] leftover ONDA.
7. Tono por estado
| Status | Frase UI | Frase que Inés podría decir (fuera de app) |
|---|---|---|
| DISPONIBLE | Disponible | «Está en el estante. No te lo llevas a casa.» |
| EN_SALA | En sala | «Alguien lo lee. No es un préstamo.» |
| PEDIDO | Pedido | «Ya hay mesa. No es el club.» |
La app no envía esos mensajes al lector en v1. El copy solo prepara el habla. No hay email de «ya está en tu mesa».
8. Capitalización y números
- Wordmark: LOMO en versales Source Serif 4.
- Código:
LM-2501(LM versales, guion, 4 dígitos). - Nombres: Inés Soto, Rafa Díez, Nora Ruiz.
- Lomos: El río Manzanares (artículo en el título, no
el-rioen UI). - Sala:
Sala 2en UI. - Fecha:
25 agosi hay línea larga. - No mezclar
lm-2501en minúsculas en UI. API puede normalizar a versales.
9. Idioma
es-ES. Fácil lectura. EN no en v1.
No mezclar «loan» ni «OPAC» en UI. En API sí: ejemplares, sala, status.
«Lector» en UI cuando hablamos de Rafa; «la bibliotecaria» para Inés; «la restauradora» solo en docs. [DECISIÓN]
10. Accesibilidad de copy
- No transmitir estado solo con color (el seal no «significa» pedido él solo).
- Filas llevan texto: Disponible / En sala / Pedido.
- Aviso de no-préstamo lleva palabras, no solo el cobre.
- Alt de fotos: objeto + lugar, no «imagen1».
- hero: «Sala de archivo de barrio en Usera; estante, mesa de lectura y caliza.»
- estante: «Lomos en un estante de sala de lectura. Cubierta de El río Manzanares y Voces del barrio.»
- mesa: «Mesa de lectura con planos abiertos. Cubierta de Planos de Usera.»
- silla: «Silla de sala de lectura junto a un lomo. Cubierta de Crónica del mercadillo.»
11. Piezas que no se escriben
| No | Motivo |
|---|---|
| «Llévatelo a casa» / «Préstamo 15 días» | Reserva ≠ préstamo · S4 |
| «Inscrito al club» / «Plaza confirmada» | Pedir ≠ club |
| «Como en la Regional» / carnet único | LOMO no es la Regional |
| «Catálogo Absys» / facetas de distrito | Lomo ≠ catálogo municipal |
| Recibido / En curso / Cerrado | No es kanban |
| «En antena» / «Pedir repetición» / ON- | Leftover ONDA |
| «Nodo aceptado» / «Alta RM-» | Leftover RAMAL |
| Lorem / «lorem ipsum lomo» | Prohibido en el case |
| Declaraciones inventadas de una biblioteca real | Verdad de catálogo |
10-accessibility.md
10 — Accesibilidad — LOMO
1. Alcance
WCAG 2.2 AA orientada al slice: mesa de datos, comando, ficha, pedir, acuse, login, mesa BIBLIO. No es una auditoría certificada. [DECISIÓN]
2. Contraste
| Par | Relación esperada |
|---|---|
Ink #1C2B28 sobre caliza #E4E0D6 | ≥ 7:1 |
Ink sobre card #FFFFFF | > 10:1 |
Card/blanco sobre mark #3E6B5E | Texto de CTA ≥ 4.5:1 |
Mute #5F6B67 sobre caliza | Meta ≥ 4.5:1 |
| Mute sobre card | Meta ≥ 4.5:1 |
Seal #9A5340 sobre caliza / card | «Pedido» / error ≥ 4.5:1 |
Prohibido: texto mark sobre ground como párrafo (cobre como cuerpo). El cobre es superficie de CTA/foco, no párrafo.
Texto sobre foto: gradient from-ink/80 bajo el titular de cubierta. No titular suelto sobre estante claro.
3. Teclado y foco
- Orden: wordmark → comando → métricas (no foco si no son controles) → filas → ficha CTA → form pedir → form login → lista mesa.
- Foco visible: ring mark 2px (ink si el fondo ya es mark).
- Filas operables con Enter / Espacio.
- Pedir mesa no se activa al pasar el foco.
- Overlay de comando:
⌘K//abre; Esc cierra; flechas recorren resultados. [DECISIÓN]
4. Targets
≥44×44 en CTA, filas, campo de comando, link Mesa, submit pedir. Campo de búsqueda altura ≥44px.
5. Nombre accesible
| Control | Nombre |
|---|---|
| Fila | Título del ejemplar (h2 o texto de fila) |
| Comando | Buscar lomo o signatura |
| Pedir mesa | Pedir mesa |
| Buscar submit | Buscar |
| Entrar | Entrar |
| Salir | Salir |
Fotos: alt de doc 09. Decorative? No: las cubiertas de ficha son contenido. Thumbs de fila tienen alt vacío si el título está al lado (alt="" + nombre en el texto). [DECISIÓN]
aria-current="page" no aplica a un rail; el wordmark no se marca current. El campo de comando en /buscar lleva aria-label.
6. Estados no solo por color
Disponible / En sala / Pedido en texto. Pedida: pantalla de acuse, no solo el botón en mark. Error: texto seal + mensaje. Empty búsqueda: «Sin lomos.»
7. Motion
prefers-reduced-motion: sin pulse. Skeletons estáticos. Cero animación de «páginas pasando» decorativa.
8. Mobile 390
Hoy: métricas wrap; filas apiladas. No carousel.
Buscar: campo sticky bajo el wordmark; resultados en columna.
Ficha: una columna; CTA al fondo del fold.
Pedir: form a columna; submit ≥44px.
Mesa: lista + pedidos a pantalla.
Comando: campo visible, no hamburger, no rail inferior de radio.
9. Autocomplete
Login: username / current-password. Buscar: type="search" · name="q". Pedir nombre: name · autocomplete="name". Sin autocomplete de dirección.
10. Idioma
html lang="es". Números y códigos leídos como texto (LM-2501). Salas «Sala 2», no room 2.
11. Búsqueda
El campo tiene label visible o aria-label="Buscar lomo o signatura". Resultados anuncian recuento (1 lomo / Sin lomos) vía texto, no solo el grid vacío.
12. Tabla de datos
La mesa de hoy es una lista de filas accionables, no una <table> opaca sin caption. Si se usa table: <caption> «Ejemplares de hoy» y encabezados Signatura / Título / Sala / Estado. En 390 las filas se apilan como cards, no se recortan columnas. [DECISIÓN]
11-privacy-security.md
11 — Privacidad y seguridad — LOMO
1. Superficie pública vs cerrada
| Recurso | Auth | PII |
|---|---|---|
| GET ejemplares | No | No (catálogo de ocupación) |
GET ejemplares ?q= | No | No |
| GET ejemplares/:code | No | No |
| POST pedir | No | Nombre de mostrador (mínimo) |
GET /ok/:code | No (solo código en URL) | No hidrata pedidos ajenos |
| GET mesa | JWT BIBLIO | Nombres de pedidos |
[DECISIÓN] El acuse no lista otros pedidos. Evita enumerar demanda de la sala.
La mesa pública no muestra nombre.
2. Datos de lector
v1 guarda solo un nombre de mostrador por pedido (pedidos.nombre). No email, no teléfono, no DNI, no carnet.
El lector no tiene fila en users. Pedir ≠ apuntarse al club.
El nombre existe para que Inés llame en sala («Rafa, sala 2»). No es una cuenta. [DECISIÓN]
3. Auth
- JWT HS256. Claims:
subuserId,sidsession,role. - Password bcrypt 12. Demo
password123solo en seed local. Hash canónico$2b$12$OEKcNck63neDJ.CrVP0lNOaXp2NG2zd2aMiGmnYY221h4ZAZ58x1m. - Guard: Bearer + sesión no revocada.
- Role BIBLIO para
/mesa. 401 sin token, 403 si no BIBLIO. - Rate limit en login.
4. Secretos
DATABASE_URL y JWT_SECRET en apps/api/.env (gitignore). Nunca en Angular.
La URI Neon del encargo es para el rewrite local; no se embebe en el bundle.
5. CORS
Allowlist localhost:4200. Previews Vercel opcionales.
6. Amenazas del slice
| Amenaza | Mitigación |
|---|---|
Enumerar /ok/LM-2501 y ver pedidos | Ok no GET de pedidos; state de navegación + catálogo público |
| POST spam de pedidos | Volumen demo; 409 si ya PEDIDO; rate Could L+1 |
| Token en localStorage | XSS = compromiso; slice L2 acepta el tradeoff de SPA [DECISIÓN] |
| Leftover CONDUCTOR / VOCAL en el mismo JWT | Seed solo BIBLIO; claims role=BIBLIO |
| Login con email de Nora | No existe la fila |
| Nombre de lector en lista pública | Fuera del JSON de GET ejemplares |
7. RGPD (modelo, no dictamen)
Base: interés de la sala en gestionar la ocupación y las reservas de mesa. Minimización: solo nombre de mostrador en v1. Sin cesión a la Regional. Derecho de supresión Could L+1 (Inés no borra en v1).
Nora no tiene acceso. No hay logs de «quién restauró el plano».
8. Lo que no hacemos
No OAuth. No cookies de marketing. No analytics de terceros en v1. No cifrado extra más allá de TLS. No cuenta de lector «por si acaso». No carnet municipal.
12-analytics.md
12 — Analítica — LOMO
1. North star
% de reservas de mesa confirmadas antes de las 11:00.
Oficio de sala. No pageviews. No «engagement con el estante». Confirmar = Inés da la mesa (fuera de app en v1; el modelo cuenta el oficio, no un PATCH). [DECISIÓN]
En v1 no hay estado CONFIRMADA: la north star es de producto, no un campo SQL. Could L+1: confirmada_at.
2. Métricas de producto (modelo)
| Métrica | Definición | Hipótesis |
|---|---|---|
| Activación lector | POST /api/ejemplares/:code/pedir 201 / visitas a / | H1 |
| Uso de comando | GET /api/ejemplares?q= con q no vacío / visitas | S-CMD |
| Tiempo a acuse | < 90 s en demo | Diseño |
| Tiempo a lectura de mesa | GET mesa desde login | Oficio |
| Integridad auth | 401 en GET mesa anónimo | Seguridad |
| Expectativa | Tickets «¿me lo llevo?» / «¿es Absys?» / «¿me apunto?» (fuera de app) | H2 |
3. Eventos (si se instrumentara)
No hay tracker en v1. Contrato de nombres por si L+1:
| Evento | Props |
|---|---|
hoy_view | ejemplares_count, disponibles, en_sala, pedidos |
buscar_query | q, results_count |
pedir_submit | code |
mesa_open | ejemplares_count, pedidos_count |
Prohibido: prestamo, club_signup, play, repetir_submit, alta_submit.
4. Lo que no medimos
Préstamos a domicilio. Fondos de Absys. Aperturas de WhatsApp (no hay dato). NPS de la Regional. Repeticiones de radio.
5. Salud
GET /api/health → { ok: true, service: "lomo-api" }. Error rate 4xx/5xx en ejemplares/pedir/mesa.
Si health dice onda-api o ramal-api, el slice no está cerrado.
13-qa-test-plan.md
13 — Plan de QA — LOMO
1. Smoke API (pnpm test:api)
- GET
/api/health→lomo-api(noonda-api, noramal-api) - GET
/api/ejemplares→ 4 codesLM-2501…LM-2504+ lead + sala + status + cover - GET
/api/ejemplares/LM-2501→ El río Manzanares · DISPONIBLE · sala 2 - GET
/api/ejemplares?q=manzanares→ incluye LM-2501; no exige los 4 - GET
/api/ejemplares?q=zzzz→[] - POST
/api/ejemplares/LM-2501/pedir{ nombre: "Rafa Díez" }→ 201pedida: true· status PEDIDO - POST
/api/ejemplares/LM-2502/pedir{ nombre: "Rafa Díez" }→ 409 (EN_SALA) - POST
/api/ejemplares/LM-9999/pedir{ nombre: "Rafa Díez" }→ 404 - GET
/api/mesasin JWT → 401 - POST
/api/auth/loginInés → BIBLIO - GET
/api/mesa→ 4 ejemplares; pedidos con nombre; no lista pública de nombres en GET ejemplares
2. Smoke UI
| # | Pasos | Esperado |
|---|---|---|
| 1 | Abrir / | Métricas + 4 filas, lead El río Manzanares, eslogan, comando |
| 2 | Tap El río Manzanares | /lomo/LM-2501 · Disponible · sala 2 |
| 3 | Pedir mesa | /pedir/LM-2501 · form nombre |
| 4 | Enviar Rafa Díez | /ok/LM-2501 + 4 oposiciones |
| 5 | /buscar + «manzanares» | El río Manzanares en resultados |
| 6 | /buscar + «zzzz» | «Sin lomos.» |
| 7 | /login Inés | /mesa lista + pedidos |
| 8 | Leer LM-2501 | No botones Aceptar/Rechazar RAMAL; no En antena ONDA |
| 9 | Logout | Hoy; /mesa pide login |
| 10 | / 390 | filas apiladas, no carousel; comando visible |
| 11 | API down | Error + Reintentar |
3. Regresión de unicidad
- No copy ONDA (programa, repetición, conductora, ON-, en antena, playlist, Patio 17).
- No copy RAMAL (nodo, alta, vocal, RM-, azotea como producto, cobertura).
- No copy TEMPLE (hora de ensayo, concierto, conserje, turno, TM-).
- No copy PREGÓN (chat, kanban, 112, parte).
- No copy PIZARRA (taller, plaza, distrito, Absys como producto).
- No préstamo a casa, no club, no Regional como CTA.
- Health no dice
onda-apiniramal-api. - Puerto 3025.
4. Accesibilidad rápida
Tab por comando y filas. Focus ring mark. Alt de fotos. Status en texto. CTA con contraste sobre mark.
5. Datos
Seed idempotente por email y code. Un POST de smoke sobre LM-2501 no borra el ejemplar. El re-seed restaura DISPONIBLE para repetir el demo.
Playwright futuro: esperar El río Manzanares, ines@lomo.barrio, no Patio 17, no nerea@onda.radio, no RM-2201, no «En antena».
6. Criterio de salida
Smoke API verde + guión UI completo + 0 leftover de dominio anterior en UI (ONDA o RAMAL).
14-dev-handoff.md
14 — Handoff de desarrollo — LOMO
1. DoD del slice
- Health
{ ok: true, service: "lomo-api" }en :3025 - 4 ejemplares seed con foto, lead, sala, status
- GET
/api/ejemplares?q=manzanares→ El río Manzanares - POST pedir público → acuse
/ok/:code - JWT BIBLIO
ines@lomo.barrio/password123 -
/mesalista + pedidos · GET JWT · no kanban - Empty / error / loading en hoy, buscar y mesa
- Copy ×4 visible
- Rutas
//buscar/lomo/:code/pedir/:code/ok/:code/login/mesa - Páginas
HoyPageBuscarPageLomoPagePedirPageOkPageLoginPageMesaPage - Paper 12 UX + 12 UI mapeados
- Docs 01–20 + README + executive
- 0 leftover
programas/repeticiones/CONDUCTOR/onda-api/nodes/altas/VOCAL
2. Contratos
Ver docs 05 y 20. JSON camelCase. SQL snake_case.
POST /api/ejemplares/:code/pedir:
{ "nombre": "Rafa Díez" }
201:
{ code, title, sala, status, pedida: true }
GET /api/mesa (JWT):
{
date,
ejemplares: [{ code, title, status, sala, cover, pedidoCount, sortOrder }],
pedidos: [{ code, title, nombre, createdAt, status }]
}
Login:
{ email: "ines@lomo.barrio", password: "password123" }
3. Mapas de pantalla
| Paper | Ruta | Componente |
|---|---|---|
| UI-01 Mesa datos | / | HoyPage |
| UI-02 Mesa mobile | / 390 | HoyPage |
| UI-03 Comando | /buscar | BuscarPage |
| UI-04 Lomo | /lomo/:code | LomoPage |
| UI-05 Lomo mobile | /lomo/:code 390 | LomoPage |
| UI-06 Pedir | /pedir/:code | PedirPage |
| UI-07 Success | /ok/:code | OkPage |
| UI-08 Login | /login | LoginPage |
| UI-09 Mesa BIBLIO | /mesa | MesaPage |
| UI-10 Empty | mismas rutas | empty branches |
| UI-11 Error+Loading | mismas rutas | error / skeletons |
| UI-00 Tokens | — | tailwind.config.js + styles.scss |
4. Tokens en código
tailwind.config.js + styles.scss. Fuentes Google: Source Serif 4 + Outfit.
Colores: ground #E4E0D6 · ink #1C2B28 · card #FFFFFF · mark #3E6B5E · mute #5F6B67 · seal #9A5340.
5. Assets
Copiar 2026-08-25-lomo/assets/lomos/*.jpg y hero.jpg a apps/web/public/assets/.
Cubiertas: lomos/estante.jpg · mesa.jpg · silla.jpg.
6. No hacer
- No reintroducir
programas/repeticiones/CONDUCTORcomo dominio vivo. - No dejar
HealthService.name = 'onda-api'ni puerto 3023. - No reintroducir
nodes/altas/VOCAL. - No documentar leftover ONDA como estado actual.
- No añadir signup de lector, préstamo, club, chat, kanban, Absys, fondo completo.
7. Arranque
cd /Users/cristian/orca/lomo-app
# apps/api/.env → DATABASE_URL Neon dawn-butterfly-79519092, JWT_SECRET, PORT=3025
pnpm --filter @repo/api start:dev
pnpm --filter @repo/web start
El rewrite corre en paralelo. Este handoff es el contrato; no se espera a Paper ni se arranca aquí.
15-roadmap.md
15 — Roadmap — LOMO
Aquí solo viven ideas de L+1 / L4 y pulido posterior.
El slice L2 del día está cerrado: mesa de datos, comando, ficha, pedir, JWT BIBLIO, mesa de pedidos.
1. Hecho (L2)
- Mesa H-DATA · métricas + 4 filas
- Comando S-CMD ·
q=manzanares - Ficha · título, sala, estado
- Form F-LEAD
/pedir/:code - Acuse
/ok/:code· reserva ≠ préstamo - Mesa JWT · lista + pedidos, no kanban
- Empty / error / loading · datos 390
- Neon
dawn-butterfly-79519092· API :3025 ·lomo-api
2. L+1 (mismo producto, más oficio)
| Item | Nota |
|---|---|
confirmada_at en pedido | North star medible en SQL |
| Marcar EN_SALA cuando se sienta | Inés PATCH; 4 filas no lo necesitan el día 1 |
| Filtro de mesa por estado | 4 filas no lo necesitan; 20 sí |
| Rate limit POST pedir | Demo no lo necesita |
| Recibo por… no: sigue sin cuenta | No email de lector |
| PWA install | Mostrador; no es Must |
| Trigram search | 4 filas no lo necesitan |
3. L4 (requiere brief nuevo de diversidad)
- Rol RESTAURADORA (Nora) + cuadrante de conservación
- Préstamo a domicilio / carnet (otro producto; no es LOMO L2)
- Fondo completo / Absys / OPAC
- Multi-sede / multi-bibliotecaria
- Chat / kanban (fue PREGÓN)
- Club de lectura / inscripción (fue PIZARRA)
- Cuenta de lector / socio
4. Fuera para siempre en este nombre
La Biblioteca Regional. Préstamo a casa el día de la petición. Catálogo municipal como producto. Programas y repeticiones (ONDA es otro día). Nodos y altas (RAMAL es otro día).
5. Criterio para abrir L+1 / L4
Solo si un día futuro elige archivo L3+ y la diversidad ALS-2 lo permite. No parche silencioso. No reabrir ONDA dentro de LOMO.
16-interaction-specs.md
16 — Especificación de interacción — LOMO
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-10 / UI-11). [DECISIÓN]
2. Mesa de datos (UI-01) + mobile (UI-02) · H-DATA
| Gesto | Resultado |
|---|---|
| Primera carga | Loading: métricas + 4 tiles card; aria-busy |
| 200 con 4 | Métricas (2 / 1 / 1) + 4 filas. Signatura, título, sala, estado |
| 200 con 0 | UI-10 empty |
| Error 5xx / red | UI-11 + Reintentar (repite GET ejemplares) |
| Tap fila | /lomo/:code |
| Tap Mesa (ghost) | /login o /mesa si hay token |
| Hover fila desktop | Ring 2px mark. Sin lift |
Foco comando / ⌘K / / | Overlay UI-03 o /buscar |
| Submit comando | /buscar?q= |
AC: título, sala y estado visibles sin hover. 3 métricas + 4 filas en el recorte (AP-21). Cero botones Prestar / Inscribirse / Play.
El aviso «Lomo ≠ catálogo municipal» es texto, no un CTA de OPAC. [DECISIÓN]
390: mismas 4 filas apiladas. No carousel. Comando visible. [DECISIÓN]
3. Comando (UI-03) · S-CMD
| Gesto | Resultado |
|---|---|
/buscar sin q | Campo + prompt de comando; no lista los 4 (eso es el hoy) |
Overlay desde / | Mismos resultados; Esc cierra; Enter abre ficha |
| Submit / debounce q | GET /api/ejemplares?q= · pending |
| 200 con hits | Filas thumb + título + sala + estado |
| 200 [] | UI-10 «Sin lomos.» |
| Error | UI-11 |
| Tap resultado | /lomo/:code |
| Query «manzanares» | Incluye El río Manzanares |
Query LM-2501 | Incluye El río Manzanares |
AC: no facetas de distrito. No H-SEARCH como home. No archivo de programas.
4. Lomo (UI-04) + mobile (UI-05)
| Gesto | Resultado |
|---|---|
| Primera carga | Loading: skeleton de ficha |
| 200 | Cubierta, título, sala, estado, copy × oposiciones, CTA |
| 404 | «Ese lomo no está.» |
| Tap Pedir mesa | /pedir/:code (F-LEAD; no POST aquí) |
| CTA si no DISPONIBLE | Disabled + «No se puede pedir esa mesa.» |
| Tap ← Hoy | / |
AC: una pantalla. Cero préstamo. Cero «Inscribirse». Cero «Pedir repetición».
5. Pedir (UI-06) · F-LEAD
| Gesto | Resultado |
|---|---|
| Carga | Form + ejemplar 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 | seal + «No se puede pedir esa mesa.» |
| 404 | «Ese lomo no está.» |
| Error red | seal + mensaje; no navega |
AC: un campo de nombre. Cero email. Cero DNI. Cero carnet.
6. Acuse (UI-07)
| Gesto | Resultado |
|---|---|
| Con código | Source Serif LM-XXXX + bloque card + 4 oposiciones |
| Sin código | «No hay ese código» + Volver al hoy |
| CTA | / hoy |
No GET de lista de pedidos. [DECISIÓN] doc 11.
7. Login (UI-08)
| Gesto | Resultado |
|---|---|
| Submit | POST login · pending |
| 200 | /mesa o next seguro (/mesa only) |
| 401 | «Email o contraseña no valen.» |
| Ya hay token | Redirect mesa |
next open-redirect: allowlist /mesa únicamente. [DECISIÓN]
8. Mesa BIBLIO (UI-09)
| Gesto | Resultado |
|---|---|
| GET mesa loading | Skeletons de fila + pedidos |
| 200 con ejemplares | Lista. DISPONIBLE primero |
| 200 pedidos | Nombre · código · hora |
| 200 pedidos [] | UI-10 «No hay pedidos.» |
| Error | UI-11 |
| Tap fila | v1: no hay ficha JWT; el gesto no navega salvo Could. [DECISIÓN] lectura |
| Salir | logout → / |
Desktop: lista + pedidos. 390: apilado. [DECISIÓN]
Cero Aceptar / Rechazar (eso fue RAMAL). Cero columnas. Cero En antena.
9. Loading / empty / error (UI-10…11)
Skeletons pulse. Empty usa titular display, no un illustration pack. Error no usa copy de 112 ni de radio.
17-prototype-map.md
17 — Mapa de prototipo — LOMO
Paper file: 01M0VVNT406AK640AK1ECY2DBR
https://app.paper.design/file/01M0VVNT406AK640AK1ECY2DBR
Este mapa es el contrato Paper ↔ docs ↔ app. No se arranca Paper desde esta suite. El archivo ya existe.
UX process → docs
| Paper | Doc |
|---|---|
| UX-00 Cover | README + 01 |
| 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 · 06 |
| UX-07 Site map | 03 |
| UX-08 Flujos | 04 |
| UX-09 Datos+permisos | 05 · 11 |
| UX-10 Métricas | 12 |
| UX-11 Research | 02 |
UI producto → app
| Paper | Ruta | Componente |
|---|---|---|
| UI-00 Tokens | — | tailwind.config.js + styles.scss |
| UI-01 Mesa datos | / | HoyPage |
| UI-02 Mesa mobile | / 390 | HoyPage |
| UI-03 Comando | /buscar | BuscarPage |
| UI-04 Lomo | /lomo/:code | LomoPage |
| UI-05 Lomo mobile | /lomo/:code 390 | LomoPage |
| UI-06 Pedir | /pedir/:code | PedirPage |
| UI-07 Success | /ok/:code | OkPage |
| UI-08 Login | /login | LoginPage |
| UI-09 Mesa BIBLIO | /mesa | MesaPage |
| UI-10 Empty | mismas rutas | empty branches |
| UI-11 Error+Loading | mismas rutas | error / skeletons |
Guión de prototipo
- Cover → Hoy (métricas + 4 filas, lead El río Manzanares).
- Comando «manzanares».
- Ficha El río Manzanares sala 2 Disponible.
- Pedir mesa · nombre.
- Acuse LM-2501 · reserva ≠ préstamo.
- Login Inés.
- Mesa BIBLIO · lista + pedidos.
- Empty / error / loading.
- Hoy 390 + lomo 390.
No hay artboard de préstamo, club, Absys, galería de radio, kanban ni nodos.
18-completeness-audit.md
18 — Auditoría de cierre — LOMO
1. Alcance L2
| 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/lomo-app | OK · rewrite en paralelo |
Neon dawn-butterfly-79519092 | OK |
API :3025 · health lomo-api | Contrato (leftover onda-api prohibido) |
| Código ejemplares + pedidos + JWT BIBLIO | Contrato paralelo |
| Cierre sin deuda del L2 | OK · roadmap solo L+1 / L4 |
2. Terna y diversidad
| Check | Evidencia |
|---|---|
| R-CL · S-CMD · H-DATA · F-LEAD | Brief + 01 + 07 |
| 0 códigos = ONDA | ONDA era R-HY · S-RAIL · H-GALLERY · F-SEARCH |
| ≥2 vs RAMAL / TEMPLE | Cmd/Data/Lead vs split/full/onb y kiosk/book |
| S-CMD, H-DATA, F-LEAD no en últimos 5 | Brief |
| Ventana 4: R-CL | R-HY (TEMPLE) + R-CL (RAMAL) + R-HY (ONDA) + R-CL |
Ground G-STONE #E4E0D6 | 00 + 07 + Tailwind |
| No leftover ONDA | 0 programas / CONDUCTOR / radio en el contrato |
3. Copy irrenunciable
Presente en hoy, ficha, pedir, acuse, pie de mesa. Ver doc 09.
- Reserva de sala ≠ préstamo a casa
- Lomo ≠ catálogo municipal
- Pedir ≠ apuntarse al club
- LOMO no es la Biblioteca Regional
4. Anti-patrones vigilados
| AP | Mitigación |
|---|---|
| AP-12 hero 2-col | H-DATA métricas + tabla |
| AP-21 card hueca | Métricas + signatura/sala/estado |
| Leftover como estado | Contrato LOMO; no se anota ONDA como producto vivo |
| Entrevistas inventadas | 02 etiquetado |
| programas/CONDUCTOR/radio | 0 en dominio; 05 + 20 |
| nodes/alta/VOCAL | 0 en dominio |
| H-SEARCH como home | Comando en /buscar; home es datos |
5. Seed
4 ejemplares · 2 DISPONIBLE · 1 EN_SALA · 1 PEDIDO · Inés BIBLIO · Rafa sin cuenta · Nora fuera.
| code | title | status | sala |
|---|---|---|---|
| LM-2501 | El río Manzanares | DISPONIBLE | 2 |
| LM-2502 | Planos de Usera | EN_SALA | 1 |
| LM-2503 | Crónica del mercadillo | PEDIDO | 3 |
| LM-2504 | Voces del barrio | DISPONIBLE | 2 |
6. Huecos conscientes (fuera)
Préstamo, login Nora, email transaccional, instrumentación analytics, fondo Absys, confirmada_at.
7. Veredicto
Slice L2 cerrado a nivel de case. El código se escribe en paralelo con el mismo contrato. Si el repo diverge (leftover ONDA), gana docs 05 + 20 tras alinear ambos. Paper no se abre en esta entrega de docs.
19-backlog-completo.md
19 — Backlog — LOMO
1. Done (Must L2)
| ID | Item |
|---|---|
| D01 | Mesa de datos 4 filas H-DATA |
| D02 | Comando S-CMD |
| D03 | Ficha /lomo/:code |
| D04 | Form /pedir/:code · F-LEAD |
| D05 | Acuse /ok/:code · POST pedir |
| D06 | Login JWT BIBLIO |
| D07 | Mesa lista + pedidos, no kanban |
| D08 | Empty / error / loading |
| D09 | Mesa datos 390 |
| D10 | Seed 4 ejemplares |
| D11 | Health lomo-api :3025 |
| D12 | Copy ×4 |
| D13 | Docs 01–20 + README + executive |
2. Could L+1 (no bloquea cierre)
| ID | Item |
|---|---|
| C01 | confirmada_at / marcar confirmada |
| C02 | PATCH EN_SALA al sentarse |
| C03 | Filtro mesa por estado |
| C04 | Rate limit POST pedir |
| C05 | PWA |
| C06 | Trigram search |
3. Explícito L4 / otro brief
| ID | Item |
|---|---|
| E01 | Login Nora / cuadrante de conservación |
| E02 | Préstamo a domicilio / carnet |
| E03 | Fondo Absys / OPAC |
| E04 | Multi-sede |
| E05 | Chat / kanban |
| E06 | Club de lectura |
4. No-backlog (rechazado)
Hero 2-col. Signup lector. leftover ONDA (programas, CONDUCTOR, onda-api) como feature. leftover RAMAL (nodes, altas, VOCAL) como feature. La Regional. Préstamo a casa. «Apúntate al club». Search-first como home.
5. Cómo usar este archivo
Done = el día. Could = L+1. E = otro cron. Nada de esta lista es deuda del L2.
20-implementation.md
20 — Implementación — LOMO
1. Resumen ejecutivo técnico
| Campo | Valor |
|---|---|
| App path | /Users/cristian/orca/lomo-app |
| API | NestJS · puerto 3025 · prefijo /api |
| Web | Angular standalone · puerto 4200 |
| Package | apps independientes (pnpm --filter) |
| DB | Neon PostgreSQL · project dawn-butterfly-79519092 |
| Tablas | users, ejemplares, pedidos, sessions |
| Auth | JWT Bearer · role BIBLIO (/mesa); datos, comando y POST pedir públicos |
| Dominio | User, Ejemplar, Pedido |
| Fecha | 2026-08-25 |
| Health | lomo-api (leftover onda-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: ejemplares + pedidos + JWT BIBLIO. Puerto 3025. Health lomo-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 ONDA (programas, repeticiones, GalleryPage, onda-api, puerto 3023) al inicio del rewrite. Eso no es LOMO. El rewrite borra ese dominio.
2. Cómo arrancar
cd /Users/cristian/orca/lomo-app
# instalar dependencias por app (pnpm --filter; no npm workspaces)
# apps/api/.env
# DATABASE_URL=postgresql://neondb_owner:npg_GDsv4KLefP5d@ep-empty-star-a69kwo3y-pooler.us-west-2.aws.neon.tech/neondb?sslmode=require
# JWT_SECRET=
# PORT=3025
# schema + seed
# api → http://localhost:3025
# web → http://localhost:4200
Credenciales
| Rol | Password | |
|---|---|---|
| BIBLIO | ines@lomo.barrio | password123 |
Hash seed: $2b$12$OEKcNck63neDJ.CrVP0lNOaXp2NG2zd2aMiGmnYY221h4ZAZ58x1m
Lector / restauradora: sin cuenta. Rafa pide en /pedir/:code. Nora no entra.
3. Schema
Al boot o vía migrate:
CREATE TABLEdeusers,sessions,ejemplares,pedidos(doc 05).- Índices:
ejemplares(code),ejemplares(status),users(email),pedidos(ejemplar_id). - Seed idempotente:
- upsert BIBLIO
ines@lomo.barrio(hash bcrypt canónico) - upsert
ejemplaresporcode(LM-2501…LM-2504) restaurando status de catálogo - upsert pedido seed de LM-2503 ·
Carmen Vidal
- upsert BIBLIO
- Dominio: solo ejemplares + pedidos + users. [DECISIÓN]
No borrar pedidos nuevos de Rafa en cada boot, salvo el re-seed explícito de demo. Upsert de ejemplares por code sí restaura status de catálogo para que el guión sea repetible. [DECISIÓN]
No generar códigos en el POST: el acuse reusa LM-2501.
Tablas (recordatorio)
| Tabla | Contenido |
|---|---|
users | BIBLIO Inés |
ejemplares | 4 lomos |
pedidos | Reservas de mesa (1 seed + las del POST) |
sessions | sid + expires_at |
DROP leftover programas, repeticiones, nodes, altas si existen en el mismo Neon. [DECISIÓN] El project dawn-butterfly-79519092 es de LOMO.
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 === BIBLIOprotege/mesa. - Públicos: health, ejemplares, ejemplares?q=, ejemplares/:code, POST pedir, login.
Oficio
| Método | Ruta | Auth | Notas |
|---|---|---|---|
| GET | /api/health | No | { ok: true, service: "lomo-api" } |
| GET | /api/ejemplares | No | sort_order asc + sala + status + cover |
| GET | /api/ejemplares?q= | No | ILIKE title/code/lead |
| GET | /api/ejemplares/:code | No | ficha |
| POST | /api/ejemplares/:code/pedir | No | INSERT pedido; status → PEDIDO; 409 si no DISPONIBLE; 404 si no hay ejemplar |
| GET | /api/mesa | JWT | 4 ejemplares + pedidoCount + lista pedidos |
Health (referencia de implementación)
HealthService.name = 'lomo-api'
main.ts PORT default 3025
Si el rewrite hereda onda-api o puerto 3023, cambiar. El puerto de LOMO es 3025.
Pedir (referencia)
ejemplar = ejemplares.byCode(code) || 404
if status !== DISPONIBLE → 409
if !nombre.trim() → 400
INSERT pedidos (ejemplar_id, nombre)
UPDATE ejemplares SET status = PEDIDO
return { code, title, sala, status: PEDIDO, pedida: true }
POST no cobra, no abre préstamo, no crea user, no inscribe al club, no mueve kanban.
JSON camelCase: sortOrder, createdAt, pedidoCount.
SQL: sort_order, created_at.
Módulos de dominio: ejemplares/, mesa/, auth/, health.
No programas/, hoy/ (JWT ONDA), repeticiones/, nodes/, altas/.
5. Frontend a implementar
| Página | Ruta | Responsabilidad |
|---|---|---|
HoyPage | / | H-DATA · GET ejemplares · métricas + 4 filas |
BuscarPage | /buscar | S-CMD · GET ?q= |
LomoPage | /lomo/:code | Ficha · CTA → pedir |
PedirPage | /pedir/:code | F-LEAD · POST pedir |
OkPage | /ok/:code | Acuse · state de navegación |
LoginPage | /login | JWT BIBLIO |
MesaPage | /mesa | Lista + pedidos · GET mesa |
Estados: loading / ready / empty / error en hoy, buscar y mesa.
Token key: lomo.accessToken.
Proxy: /api → :3025.
Tokens Tailwind: ground / ink / card / mark / mute / seal. Fuentes Source Serif 4 + Outfit.
Chrome comando: campo «buscar lomo o signatura» → /buscar. Wordmark → /. Mesa → /mesa.
Renombrar leftover GalleryPage / ProgramaPage / HoyPage JWT ONDA / SearchPage → las siete páginas de arriba. [DECISIÓN]
Nota: HoyPage en LOMO es la home pública H-DATA, no la mesa JWT de ONDA.
6. Seed visible en UI
| Código | Título | Status | Sala | Cover |
|---|---|---|---|---|
| LM-2501 | El río Manzanares | DISPONIBLE | 2 | /assets/lomos/estante.jpg |
| LM-2502 | Planos de Usera | EN_SALA | 1 | /assets/lomos/mesa.jpg |
| LM-2503 | Crónica del mercadillo | PEDIDO | 3 | /assets/lomos/silla.jpg |
| LM-2504 | Voces del barrio | DISPONIBLE | 2 | /assets/lomos/estante.jpg |
Playwright: esperar El río Manzanares, El lomo, no el prestado., ines@lomo.barrio.
No esperar Patio 17, nerea@onda.radio, ON-2301, En antena, Azotea Palomeras, RM-2201.
7. Smoke
apps/api/scripts/test-api.mjs · pnpm test:api contra :3025.
Cubre health lomo-api, 4 ejemplares, q=manzanares, POST pedir, 409 EN_SALA, 404 code, 401 mesa, login BIBLIO, lista 4, pedidos con nombre.
8. DoD técnico
Ver doc 14. Este archivo no lista leftover de otro día como estado del producto. El contrato vivo es LOMO. ONDA es N−1, no el dominio de este repo.