En esta página 00 — Day brief · 2026-08-27 · PIÑÓN 0%

00-day-brief.md

00 — Day brief · 2026-08-27 · PIÑÓN

Decisiones ALS-2 BRIEF

CampoValor
Fecha2026-08-27
NombrePIÑÓN
ComplejidadNivel 2 (no L1 consecutivo tras BOBINA)
SectorMovilidad urbana / taller de bicicletas de barrio (nave Arganzuela · Legazpi)
TipoBento del taller + configurador de encargo + mesa MECÁNICO JWT
PlataformaWeb responsive (bento en el móvil · mesa en el portátil del mostrador)
RegistroR-HY — identidad de oficio clásica + bento/configurador
ShellS-TOP — Taller · Encargo · Mesa
HomeH-BENTO foto-led Deriva — tile de nave a sangre (≥40 % del recorte 16/10) + 3 datos + 4 bicis
FlujoF-CMP — configurar el arreglo (rueda / frenos / cadena / revisión), luego dejar la bici
Por qué no BOBINANo S-DOCK / H-FEED / F-STORY; no cineclub; no velvet
Por qué no LOMONo S-CMD / H-DATA / F-LEAD; no archivo; no mesa de ejemplares
Por qué no MATIZMATIZ era S-BOTTOM+H-BENTO+F-EDIT (N−8). Aquí S-TOP + F-CMP; el núcleo es el configurador, no el editor de gramos
Por qué no ZAGUÁNZAGUÁN era S-WIZ+H-WIZARD+F-CMP. Aquí no hay wizard de criterios; hay bento de taller
Por qué no TROCHANo flota de última milla; la bici se deja, no se reparte
Por qué no VOLTANo club ni plaza; encargo ≠ cita de fitness

Terna unicidad

R-HY · S-TOP · H-BENTO · F-CMP

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

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

Ground (CRON §5.6)

  • Familia: G-GRAPHITE
  • Hex: #2C3033
  • Por qué: suelo de nave y esmalte de cuadro, no terciopelo (BOBINA), no caliza (LOMO), no cartel blanco (ONDA), no hielo (RAMAL), no tinta de flight case (TEMPLE).

Mood visual (Paper)

  • Candidatos: nocturnal/fixie neón (primer instinto taller cool), industrial, rusted, arid, botanical
  • Elegido: industrial — no el primer instinto Rapha/neón. Un taller de Legazpi se lee con esmalte, hormigón y naranja de reflector, no con LED de tienda de fixies.
  • Paleta:
    • #2C3033 grafito de nave (ground)
    • #F3F1EC ficha / cream
    • #1A1C1B card oscura
    • #E24A17 naranja de reflector (mark)
    • #8B8E8A mute
    • #C5C8C4 cromo (poco)
  • Tipo: Spectral display · Sora UI

Home foto-led (D-P1-09)

UI-01 = Deriva en bento: tile de la nave a sangre (≥40 % del recorte 16/10) + lead + 3 datos (en taller / listas / esperan) + 4 bicis. No feed. No H-DATA tabla. Cuota last 6: BOBINA+LOMO = 2 → PIÑÓN es el 3º.

Alcance L2 must

  1. Home bento foto-led: 4 bicis + 3 métricas
  2. Configurador de arreglo (F-CMP)
  3. Dejar la bici (nombre, teléfono, color del cuadro)
  4. Success con código de encargo
  5. Login JWT MECÁNICO
  6. Mesa de ganchos (EN_TALLER / LISTA / ESPERA) — no kanban
  7. Empty / error / loading / mobile bento
  8. ≥12 UX + ≥10 UI

Microcopy duro

  • Dejar la bici ≠ comprar el taller. No se vende una bici nueva.
  • Encargo ≠ cita de fitness. No reserva una clase.
  • Recoger ≠ alquilar. No es un bike-share.
  • PIÑÓN no es Decathlon.

Supuestos

  • S1: El taller atiende 2–4 bicis/día en el slice; demo 4. [SUPUESTO]
  • S2: El vecino deja la bici sin cuenta. JWT solo MECÁNICO. [SUPUESTO]
  • S3: Repartidor y dueño de la nave fuera del producto. [SUPUESTO]
  • S4: Sin e-commerce, sin GPS, sin chat, sin kanban. [DECISIÓN]

Hipótesis

IDSeñal
H1Un bento de ganchos reduce «¿está lista?» por WhatsApp
H2El configurador evita el «arréglame lo que sea» que no cabe en un L2
H3Cuatro bicis bastan; no hace falta el stock de Decathlon

Seed demo

CódigoBiciArregloEstado
PIN-2701Orbea urbana verdeFrenosEN_TALLER
PIN-2702BH paseo cremaRevisiónLISTA
PIN-2703Classic fold negraRuedaEN_TALLER
PIN-2704Trek niño azulCadenaESPERA

Modelos son catálogo demo. No es un taller real ni un acuerdo con Orbea. [SUPUESTO de taller]

JWT

nuria@pinon.taller / password123 · rol MECANICO · API :3027

00-paper-reference.md

Paper reference · PIÑÓN

URLhttps://app.paper.design/file/01M110K5JHDQ899C360KC4D0WD
File ID01M110K5JHDQ899C360KC4D0WD

UX-count: 12 UI-count: 12

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

IDNombreContenido
UX-00CoverIdentidad industrial, terna, foto nave
UX-01StakeholdersNuria MECÁNICO, Pablo VECINO, fuera de slice
UX-02PersonasPablo 34 / Nuria 41
UX-03JTBDFuncional / emocional / social
UX-04StoriesMust dejar bici / configurar / mesa
UX-05JourneyDescubrir → configurar → dejar → código
UX-06BlueprintFrontstage / mesa / Neon / 409
UX-07Site mapS-TOP Taller · Encargo · Mesa
UX-08FlujosPOST encargos + JWT mesa
UX-09Datos + permisosBike / Request / User
UX-10MétricasNorth star encargos recogidos
UX-11Research notesEtiquetado COMPROBADO/SUPUESTO/HIPÓTESIS/DECISIÓN

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

IDNombreFlujo
UI-01Taller bento foto-ledHome Deriva-split ≥40 %
UI-02ConfiguradorF-CMP 4 piezas
UI-03Dejar biciNombre + teléfono
UI-04SuccessPIN-2705 copy duro
UI-05LoginJWT MECÁNICO
UI-06Mesa4 ganchos, no kanban
UI-07EmptyNo hay ganchos hoy
UI-08Error409 cupo ESPERA
UI-09LoadingSkeletons
UI-10TokensG-GRAPHITE industrial
UI-11Mobile bentoCore mobile
UI-12Mobile encargoConfigurador 390

Media

  • assets/hero.jpg
  • assets/bicis/orbea.jpg
  • assets/bicis/bh.jpg
  • assets/bicis/fold.jpg
  • assets/bicis/trek.jpg

01-project-definition.md

01 — Definición de proyecto — PIÑÓN

1. Identidad

CampoValor
NombrePIÑÓN
SignificadoPiñón es el engranaje del taller de barrio, no el lineal de una gran superficie. Se entra a la nave; se sale habiendo dejado la bici.
Eslogan«El gancho, no el lineal.»
Una fraseBento foto-led de ganchos + configurador de arreglo + dejar la bici + mesa MECÁNICO JWT.
SectorMovilidad urbana / taller de bicicletas de barrio (nave Arganzuela · Legazpi, Madrid)
TipoWeb L2 — bento H-BENTO Deriva + chrome S-TOP + configurador F-CMP + mesa JWT — Nivel 2, vertical slice de taller
PlataformaWeb responsive (bento en el móvil · mesa en el portátil del mostrador)
Mercado demoEspaña · Madrid · Arganzuela / Legazpi (un taller de nave, no Decathlon)
Idiomaes-ES
Fecha caso2026-08-27
TernaR-HY · S-TOP · H-BENTO · F-CMP

[COMPROBADO] Nombre, terna, nivel, sector, ground y paleta salen de docs/00-day-brief.md.
[SUPUESTO de taller] Arganzuela / Legazpi / Orbea / BH / Trek es atrezzo de mercado, no un taller real ni un acuerdo de marca.

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

2. Problema

Principal (hipótesis de diseño)

[HIPÓTESIS] El vecino de Legazpi no necesita comprar una bici nueva ni reservar una clase: necesita dejar la suya y saber si está lista sin preguntar por WhatsApp. Hoy eso vive en un recado al mostrador, un grupo del barrio y una expectativa de «tienda». Dejar la bici se lee como comprar el taller; el encargo se lee como cita de fitness; recoger se lee como alquilar; el producto se lee como Decathlon. [SUPUESTO] Un taller de barrio atiende 2–4 bicis/día; no opera un lineal ni un GPS de flota.

Secundarios

ProblemaQuién lo sufreEfecto
«¿Está lista?» por WhatsAppVECINO (Pablo)Pregunta, espera, pasa de recoger
Dejar la bici se lee como comprarVECINO + NuriaEsperan catálogo, talla, precio de cuadro nuevo
El encargo se lee como citaPabloEsperan slot, coach, clase
Recoger se lee como alquilarPablo + AmparoEsperan candado, app de bike-share, minutos
La mesa MECÁNICO se lee como kanbanMECÁNICO (Nuria)Esperan Recibido / En curso / Cerrado
El dueño pide lineal y GPS el día 1NaveEl L2 se vuelve Decathlon + TROCHA

Supuestos (no investigación primaria propia)

  • S1: El taller atiende 2–4 bicis/día en el slice; demo 4. [SUPUESTO]
  • S2: El vecino deja la bici sin cuenta. JWT solo MECÁNICO. [SUPUESTO]
  • S3: Repartidor y dueño de la nave fuera del producto. [SUPUESTO]
  • S4: Sin e-commerce, sin GPS, sin chat, sin kanban. [DECISIÓN]

Hipótesis de producto

IDHipótesisSeñal de validación (futura)
H1Un bento de ganchos reduce «¿está lista?» por WhatsApp% de visitas a / que consultan estado sin mensaje
H2El configurador evita el «arréglame lo que sea» que no cabe en un L2POST /encargos con job explícito (rueda / frenos / cadena / revisión)
H3Cuatro bicis bastan; no hace falta el stock de Decathlon0 catálogo de venta; Nuria opera 4 ganchos

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

3. Propuesta de valor

ParaValor
VECINO (Pablo Mora)Ve 4 ganchos en el bento, configura el arreglo, deja la bici, se lleva el código. Nadie le pide cuenta ni le vende un cuadro.
MECÁNICO (Nuria Vega)Ve la mesa de ganchos (ESPERA / EN_TALLER / LISTA). No mueve columnas. No vende bicis.
VECINA MAYOR (Amparo Díaz)Fuera del login; la documentación y a11y la contemplan (contraste cream/grafito, targets, copy legible).
Taller PIÑÓNUna superficie mínima: bento + configurador + mesa, sin Decathlon y sin GPS.

No es PIÑÓN

ExcluidoPor qué
Lineal / venta de bici nuevaDejar la bici ≠ comprar el taller
Cita de fitness / slot de claseEncargo ≠ cita de fitness
Alquiler / bike-share / minutosRecoger ≠ alquilar
Decathlon / gran superficiePIÑÓN no es Decathlon
Catálogo completo / miles de SKUH3 · S1
Chat de vecinos / kanbanEso fue PREGÓN (H-CHAT / F-KAN)
Flota de última milla / GPSEso fue TROCHA
Club / plaza / reserva de claseEso fue VOLTA (encargo ≠ cita)
Wizard de criterios inmobiliariosEso fue ZAGUÁN (S-WIZ / H-WIZARD / F-CMP de fincas)
Editor de gramos / fichas de colorEso fue MATIZ (S-BOTTOM / F-EDIT)
Feed de noches / pedir butacaEso fue BOBINA (H-FEED / F-STORY)
Mesa de ejemplares + comandoEso fue LOMO (H-DATA / S-CMD / F-LEAD)
Hero 2-col + 3 cards de «tu taller»Anti-patrón AP-12; contradice H-BENTO Deriva
App de 40.000 SKU y CMSL2 compacto, no Decathlon

4. Objetivos

Negocio / caso de estudio

  • Demostrar vertical slice L2 taller de barrio con Bike + Request + JWT MECÁNICO.
  • Portfolio coherente: Paper (12 UX + 12 UI) + docs + app runnable.
  • Terna R-HY · S-TOP · H-BENTO · F-CMP frente a BOBINA (dock/feed/story), LOMO (cmd/datos/lead) y ONDA (rail/galería/archivo).
  • No encadenar otro L1 tras BOBINA. [DECISIÓN]

Usuario

RolObjetivo medible en demo
VECINOVer 4 bicis, configurar un arreglo, dejar la bici y ver el success en < 90 s, sin cuenta
MECÁNICOEntrar a mesa, ver ganchos ESPERA / EN_TALLER / LISTA en < 45 s
VECINA MAYORNo encuentra login; a11y y docs la contemplan; no es rol de sistema

No objetivos v1 (explícitos)

  • E-commerce, precio, pago, lineal de bicis nuevas
  • GPS, tracking, flota, última milla
  • Cita de fitness, slot, coach, plaza
  • Alquiler, bike-share, candado conectado
  • Chat, kanban, columnas Recibido / En curso
  • Cuenta de vecino, socio, newsletter
  • Multi-nave, multi-mecánico
  • App nativa ni notificaciones push
  • Rol repartidor / dueño autenticado
  • Sesiones, butacas, PROGRAMADOR (BOBINA es otro día)
  • Ejemplares, BIBLIO, comando (LOMO es otro día)
  • Programas, repeticiones, CONDUCTOR (ONDA es otro día)
  • Fórmulas, COLORISTA, editor de gramos (MATIZ es otro día)

5. Roles y permisos (resumen)

AcciónAnónimo (vecino)MECÁNICOVECINA MAYOR
Ver taller /Sin cuenta; usa la pública
Ver configurador /encargoSí (no es el job)
POST dejar biciSí (no es el job)Sí (mismo form público)
Ver success /ok/:code (código en URL)
Ver mesa /mesaNo (401 / redirect)No
GET /api/mesa401
Ver teléfonos de encargosNoSí (mesa)
Vender bici nuevaNo (no existe)NoFuera
GPS / repartoCopy: fueraCopy: fueraOficio fuera de app

[DECISIÓN] Un solo rol autenticado: MECÁNICO. El vecino no es un usuario del sistema: es autor/autora de un request. Amparo no es un rol de sistema el día 1.

6. Métricas (modelo, no instrumentadas en v1 salvo base)

TipoMétricaDefinición
North Star% de bicis LISTA recogidas sin un WhatsApp de «¿está lista?»Oficio de gancho, no pageviews
Activación vecino1.er POST /api/encargos con codeH2
Integridad de expectativaReclamaciones «¿compro la bici?» / «¿es una cita?» / «¿alquilo?»H2 + microcopy
Integridad de authGET /api/mesa sin token → 401; POST /api/encargos sin token → 201Bento público + mesa MECÁNICO cerrada
SaludError rate API bicis / encargos4xx/5xx

7. Alcance funcional v1 (L2)

MóduloIncluido
Home bentoGET /api/bicis · tile de nave a sangre + 3 métricas + 4 bicis
Configurador/encargo paso 1 · rueda / frenos / cadena / revisión
Dejar bici/encargo paso 2 · nombre, teléfono, color del cuadro
EncargoPOST /api/encargos → success; dejar ≠ comprar
AuthPOST /api/auth/login → JWT MECÁNICO
Mesa MECÁNICOGET /api/mesa JWT · ganchos ESPERA / EN_TALLER / LISTA, no kanban
Estados UIEmpty (0 bicis), loading skeleton, error de red
MobileBento ~390px · S-TOP Taller · Encargo · Mesa · targets ≥44px
Seed1 MECÁNICO, 4 bicis (2 EN_TALLER, 1 LISTA, 1 ESPERA)
SaludGET /api/health{ ok: true, service: "pinon-api" }

8. Criterios de aceptación de producto

  1. / es el bento foto-led Deriva (tile de nave a sangre ≥40 % del recorte 16/10 + lead + 3 datos + 4 bicis). No pide cuenta. No es un hero 2-col + 3 cards. No es un feed. No es una mesa de datos.
  2. Un vecino puede ver 4 bicis, configurar un arreglo, dejar la bici y obtener success en /ok/PIN-XXXX.
  3. /ok/:code dice explícitamente que dejar la bici no es comprar el taller y que encargo no es cita de fitness.
  4. La UI dice explícitamente que recoger no es alquilar y que PIÑÓN no es Decathlon.
  5. Sin token, GET /api/mesa responde 401. POST /api/encargos y GET /api/bicis son públicos.
  6. Un POST de encargo no crea user, no cobra, no abre un lineal, no mueve kanban, no enciende GPS.
  7. Un MECÁNICO inicia sesión y ve 4 bicis (2 EN_TALLER, 1 LISTA, 1 ESPERA) en el seed.
  8. El tablero autenticado es una mesa de ganchos. No es un kanban de 3 columnas. No es un split lista | ficha.
  9. Fotos reales en las cubiertas seed (assets bicis/*).
  10. Chrome S-TOP: Taller · Encargo · Mesa. Home sin dock de cineclub y sin comando de archivo.
  11. Rutas solo las del doc 03. No existen /buscar, /sesion, /pedir, /lomo, /cita, /tienda.
  12. GET /api/health devuelve service: "pinon-api" (no bobina-api, no lomo-api).
  13. El bento público no muestra teléfonos de otros vecinos; la mesa MECÁNICO sí muestra encargos con nombre y teléfono.
  14. PIN-2702 aparece LISTA; PIN-2704 aparece ESPERA; no se vende ninguna.

9. Stack y artefactos

CapaDetalle
FrontendAngular + Tailwind · puerto 4200
BackendNestJS · puerto 3027
DBNeon PostgreSQL · project dedicado PIÑÓN (DATABASE_URL)
AuthJWT (MECÁNICO)
DiseñoPaper 01M110K5JHDQ899C360KC4D0WD
Repo app/Users/cristian/orca/pinon-app/ · GH Criscode2022/pinon-app
Packagepnpm

[COMPROBADO] Puerto, Paper file ID y path de app constan en el encargo.
El código vive en pinon-app con este contrato. Este doc es la fuente de verdad del slice L2.

10. Riesgos y mitigaciones

RiesgoImpactoMitigación v1
Expectativa de Decathlon«¿Compro la bici?»Copy «Dejar la bici ≠ comprar el taller»
Expectativa de fitnessSlot, clase, coachCopy «Encargo ≠ cita de fitness»
Expectativa de alquilerBike-share, minutosCopy «Recoger ≠ alquilar»
Expectativa de gran superficieLineal, SKU, tallaCopy «PIÑÓN no es Decathlon»
Expectativa de kanbanRecibido / En cursoMesa de ganchos, no columnas de flujo
Leftover BOBINAsesiones, PROGRAMADOR, bobina-apiContrato PIÑÓN; health pinon-api; 0 copy de sala
Leftover LOMOejemplares, BIBLIO, comandoDominio bicis + requests + MECANICO
E-commerce el día 1Alcance L3 disfrazadoH3: cuatro ganchos
GPS el día 1Alcance TROCHAS4; roadmap L3
Cuenta de vecinoRompe S2Sin signup; POST público con nombre + teléfono
Home percibida como landing de tiendaPérdida de H-BENTO / AP-12Deriva tile + 3 datos + 4 bicis
Home percibida como feedConfundir con BOBINAH-BENTO, no H-FEED
Home percibida como mesa de datosConfundir con LOMOBento, no métricas tabulares ni comando
Confundir con VOLTA (cita)Expectativa de claseEncargo de arreglo, no plaza
Confundir con TROCHA (flota)Expectativa de GPSLa bici se deja, no se reparte
0 bicisBento vacío sin oficioEmpty «Aún no hay ganchos.»
WhatsApp paraleloH1 no se mideNorth star etiquetada como modelo
Mark naranja como texto de párrafoContraste WCAGMark pinta CTA/foco; cream escribe sobre grafito

11. Glosario

TérminoDefinición en PIÑÓN
PiñónEngranaje / oficio del taller; el producto, no el lineal ni el alquiler
BiciCuadro en gancho (bicis); no es un SKU de Decathlon
CódigoPIN-XXXX; identifica el encargo / la bici
EncargoArreglo configurado (rueda / frenos / cadena / revisión); no es cita de fitness
GanchoPlaza física en la nave; superficie de la mesa
TallerSuperficie H-BENTO pública de ganchos; bento sobre foto de nave
Mesa (MECÁNICO)Superficie JWT de Nuria (ganchos por estado, no kanban)
RequestPOST 201; no significa compra ni alquiler
SuccessCódigo (PIN-XXXX); no es un ticket de tienda
EsperaEstado ESPERA; aún no se ha puesto a trabajar
En tallerEstado EN_TALLER; está en el gancho de trabajo
ListaEstado LISTA; se puede recoger
EntregadaEstado ENTREGADA; ya no cuelga; fuera de la mesa v1
S-TOPChrome: Taller · Encargo · Mesa
MECÁNICOUsuario autenticado que opera la mesa
VECINOAutor/autora del encargo; no tiene fila en users
VECINA MAYORPersona de docs / a11y; fuera del login
DecathlonGran superficie; fuera. Dejar ≠ comprar
FitnessCita / clase; fuera. Encargo ≠ cita
AlquilerBike-share; fuera. Recoger ≠ alquilar
IndustrialMood: esmalte, hormigón, naranja de reflector; no LED de fixie
GroundGrafito de nave #2C3033
CreamTexto / ficha #F3F1EC
CardSuperficie oscura #1A1C1B
MarkNaranja de reflector #E24A17
Mute#8B8E8A
ChromeCromo #C5C8C4, poco
DerivaHome foto-led: tile de nave a sangre + 3 datos + 4 bicis

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

IDDecisiónAlternativa descartada
D1Home = bento foto-led Deriva (H-BENTO)Hero 2-col + 3 cards (AP-12) · feed (BOBINA) · mesa de datos (LOMO)
D2Shell top Taller · Encargo · Mesa (S-TOP)Dock de cineclub · comando de archivo · rail de radio · bottom tabs MATIZ
D3Registro híbrido: oficio clásico + bento/configurador (R-HY)Neón Rapha/fixie (primer instinto) · velvet BOBINA · mineral LOMO
D4Flujo F-CMP (configurar arreglo → dejar bici)F-STORY, F-LEAD, F-EDIT, F-KAN, wizard de criterios
D5Mood industrialNocturnal/fixie neón (primer instinto), rusted, arid, botanical
D6Un rol autenticado MECÁNICOMulti-rol repartidor / vecino / dueño
D7Status ESPERA / EN_TALLER / LISTA / ENTREGADAKanban de 3 columnas; «vendida»; «en ruta»
D8Vecino sin cuentaSignup, socio, carnet de taller
D9Bento público no lista teléfonosTablero público enumerable
D10POST público de encargo con nombre + teléfono + colorFormulario de DNI + pago + talla
D11Ground G-GRAPHITE #2C3033G-VELVET, G-STONE, G-SIGN, G-ICE, G-INK
D12Success en /ok/:codeToast único sin pantalla
D13Configurador y dejar bici en /encargo (dos pasos, una ruta)POST oculto en el tile; wizard 5 pasos
D14Mesa MECÁNICO = ganchos por estado, no kanban ni splitRecibido / En curso / Cerrado; lista | ficha RAMAL
D15Bento público + mesa JWT (no auth-first total)Todo cerrado (rompería S2) · todo abierto (rompería mesa)
D16Sin e-commerce / GPSPrecio + tracking
D17Leftover BOBINA no es el productoMantener sesiones / PROGRAMADOR / bobina-api
D18Health pinon-api · puerto 3027leftover bobina-api · :3026
D19Job de arreglo = una pieza (rueda | frenos | cadena | revisión)«Arréglame lo que sea»; carrito multi-SKU
D20Encargo nuevo entra en ESPERAEntra directo EN_TALLER (saltaría el gancho de cola)

13. Relación con el día anterior

CaseTernaPor qué PIÑÓN no lo copia
BOBINA (N−1)R-IN · S-DOCK · H-FEED · F-STORYNo cineclub, no feed, no dock, no butaca, no PROGRAMADOR
LOMO (N−2)R-CL · S-CMD · H-DATA · F-LEADNo archivo, no ejemplares, no comando, no BIBLIO, no mesa de datos
ONDA (N−3)R-HY · S-RAIL · H-GALLERY · F-SEARCHComparte R-HY; no radio, no cubiertas, no repetición, no rail
MATIZ (N−8)R-HY · S-BOTTOM · H-BENTO · F-EDITComparte H-BENTO; aquí S-TOP + F-CMP; el núcleo es el configurador, no el editor de gramos
ZAGUÁNR-IN · S-WIZ · H-WIZARD · F-CMPComparte F-CMP; no hay wizard de criterios; hay bento de taller
TROCHANo flota de última milla; la bici se deja, no se reparte
VOLTANo club ni plaza; encargo ≠ cita de fitness

[COMPROBADO] El brief fija terna R-HY · S-TOP · H-BENTO · F-CMP. 0 códigos iguales a N−1 (BOBINA). ≥2 distintos vs N−2 (LOMO) y N−3 (ONDA). S-TOP, H-BENTO y F-CMP no están en los últimos 5. Ground G-GRAPHITE #2C3033, no G-VELVET ni G-STONE.

02-ux-research-strategy.md

02 — Estrategia de investigación UX — PIÑÓN

Importante: este documento contiene artefactos de diseño y razonamiento secundario.
No hay entrevistas de campo primarias ni estadísticas inventadas presentadas como dato medido.
Etiquetas: [COMPROBADO] en producto, [SUPUESTO], [HIPÓTESIS], [DECISIÓN].

1. Objetivos de investigación (del caso)

ObjetivoMétodo en este casoSalida
Entender actores del taller de barrioModelado de stakeholders + personas§3–4
Definir job «dejar la bici y saber si está lista sin WhatsApp»JTBD + stories Must§5–6
Mapear fricción WhatsApp / Decathlon / fitness / alquiler → bento + configuradorJourney + service blueprint§7–8
Traducir a requisitos L2 bento + F-CMP + dejar + mesaMatriz hallazgo → requisito → feature§9

2. Fuentes y límites

Fuentes admisibles (secundarias / operativas)

  • Conocimiento general de talleres de barrio (mostrador, gancho, recado de «¿está lista?», 2–4 bicis al día, mecánica que opera la nave, dueño y reparto fuera del producto día 1).
  • Analogía operativa con superficie pública + panel JWT de la serie daily.
  • Restricciones ALS-2: no Decathlon, no cita de fitness, no alquiler, no flota GPS, no cineclub, no archivo, no editor de gramos.

Límites éticos de verdad

ProhibidoPermitido
«El 58% de vecinos de Legazpi pregunta por WhatsApp si está lista» sin fuente«[SUPUESTO] Pablo abre el taller desde el móvil»
Citas de entrevistas ficticias como campo realQuotes de persona etiquetadas como constructo de diseño
Volumen medido «23 Orbea/semana» como KPI de mercadoBicis de seed de producto, etiquetadas como demo
Taller oficial Orbea / BH en Arganzuela 2026Bicis de seed; Nuria, Pablo y Amparo son personas de diseño
«Pablo existe y nos dijo…»Pablo Mora es persona de diseño

3. Stakeholders

StakeholderInfluenciaInterésNecesidad principal
MECÁNICO (Nuria)AltaMuy altaVer ganchos sin kanban ni lineal
VECINO (Pablo)Alta en el encargoMuy altaDejar la bici y saber el código, sin cuenta
VECINA MAYOR (Amparo)Media formal, baja en producto día 1AltaLeer el taller con contraste y targets; sin login forzado
Nave / taller de barrioAlta formalAltaQue se vea qué cuelga; que no se confunda con Decathlon ni con un gimnasio
Decathlon / gran superficieCompetencia / analogía falsaFuera de alcance; no clonar lineal
Club de fitness / VOLTAAnalogía falsa de citaFuera; Encargo ≠ cita de fitness
Bike-share / alquilerAnalogía falsa de recogerFuera; Recoger ≠ alquilar
TROCHA / flotaAnti-patrón de GPSFuera; la bici se deja, no se reparte
BOBINA / cineclubAnti-patrón N−1Fuera; no sesiones, no butaca, no feed
LOMO / archivoAnti-patrón N−2Fuera; no ejemplares, no BIBLIO, no comando
Grupo de WhatsApp del barrioCanal paraleloNo es el backoffice; H1 apunta a reducirlo
Dueño de la nave / repartidorS3 fueraFuera del JWT

Mapa de poder (resumen)

  • Decisor de adopción: el taller (quién cuelga las bicis) y, en uso diario, Nuria (quien mira ganchos).
  • Usuario frecuente de dejar bici: VECINO (bento + configurador + form, sin cuenta).
  • Usuario frecuente de oficio: MECÁNICO (mesa /mesa).
  • Riesgo de rechazo: si el success parece un ticket de tienda; si el tile parece un SKU de Decathlon; si hay que crear cuenta; si la mesa parece un kanban; si el encargo parece una cita.

4. Personas

P1 — Nuria Vega · MECÁNICO

CampoDetalle
Edad / contexto39 años; mecánica del taller PIÑÓN en nave de Arganzuela / Legazpi; mesa de ganchos, no de lineal
DigitalFluida en el portátil del mostrador; el bento público no es su herramienta principal, pero lo mira
GoalsVer qué bicis esperan, cuáles están en taller, cuáles están listas para recoger
PainsWhatsApp a deshora; «¿me venden una Orbea?»; un kanban que no es su oficio; un GPS que no es su job de hoy
Quote de diseño«Quiero ver los ganchos. No una tienda y no un gimnasio.»
Email demonuria@pinon.taller / password123

Escenario: Entra a /login, abre /mesa, lee PIN-2702 BH paseo LISTA, ve los encargos. El copy dice que recoger no es alquilar.

[COMPROBADO] Nombre de cuenta, email demo y rol salen del encargo. Edad y apellido son constructo de diseño. [DECISIÓN]

P2 — Pablo Mora · VECINO

CampoDetalle
Edad / contexto34 años; vive en Legazpi; deja la bici cuando falla un freno o una rueda; no quiere «otra cuenta de tienda»
DigitalMóvil desde la acera o el sofá; no se hace socio si puede evitarlo
GoalsVer qué cuelga en la nave; configurar el arreglo; dejar la bici; llevarse un código
PainsEl WhatsApp dice «creo que está lista el jueves»; abre Decathlon; le venden un cuadro; cree que reserva una clase
Quote de diseño«Solo quiero dejar la bici. No me hagas una tienda.»

Escenario: Abre / en el móvil, ve 4 ganchos, toca Encargo, elige frenos, escribe nombre y teléfono y color, lee «dejar la bici ≠ comprar el taller» y el código PIN-XXXX.

[COMPROBADO] El gesto (vecino, deja sin cuenta) sale del encargo. Nombre y edad son constructo de diseño. [DECISIÓN]
Pablo no tiene fila en users. [DECISIÓN]

P3 — Amparo Díaz · VECINA MAYOR (docs / a11y)

CampoDetalle
Edad / contexto71 años; vecina de Arganzuela; lee el taller con calma; contraste y tamaño importan
DigitalNo tiene login en el slice L2; usa la superficie pública si el contraste y los targets aguantan
GoalsEntender cómo dejar la bici, sin mistificarse con Decathlon ni con un alquiler
PainsTexto mute sobre grafito; botones pequeños; copy de gran superficie
Quote de diseño«Si no leo el gancho, no dejo la bici. No me vendáis una.»

[DECISIÓN] no hay cuenta de Amparo en v1; a11y la contempla en docs 10. Nombre y edad son constructo de diseño.

5. JTBD

Job principal (vecino)

Cuando la bici falla (rueda, frenos, cadena o toca revisión), quiero configurar el arreglo y dejarla en el taller sin preguntar por WhatsApp, para que Nuria la cuelgue sin que eso signifique compra, cuenta, cita ni alquiler.

Job principal (mecánica)

Cuando hay ganchos ocupados y encargos nuevos, quiero ver ESPERA / EN_TALLER / LISTA, para mover el oficio del taller sin un kanban ni un lineal.

Jobs que PIÑÓN no hace

JobPor qué no
Comprar una bici nuevaDejar la bici ≠ comprar el taller · S4
Reservar una clase / plazaEncargo ≠ cita de fitness
Alquilar / desbloquear una biciRecoger ≠ alquilar
Sustituir a DecathlonPIÑÓN no es Decathlon
Rastrear GPS / última milla≠ TROCHA · S4
Pedir butaca de cineclub≠ BOBINA
Pedir mesa de un lomo≠ LOMO
Editar gramos de color≠ MATIZ
Comparar 3 fincas≠ ZAGUÁN

6. Stories Must (v1)

IDComoQuieroPara
US-01VecinoVer bento foto-led de 4 bicis + 3 métricasDistinguir taller de Decathlon / feed / tabla
US-02VecinoConfigurar el arreglo (rueda / frenos / cadena / revisión)Evitar «arréglame lo que sea»
US-03VecinoDejar la bici (nombre, teléfono, color) y ver success PIN-XXXXDejar constancia, no comprar
US-04MecánicaEntrar con JWTAbrir la mesa de ganchos
US-05MecánicaVer ESPERA / EN_TALLER / LISTA + encargosOficio sin kanban
US-06AmbosVer empty / error / loadingNo quedarse en blanco
US-07VecinoUsar S-TOP en 390Taller · Encargo · Mesa sin hamburger

Could (fuera de L2, solo L3): GPS, e-commerce, login de Amparo, pago, chat, cuenta de vecino.

7. Journey (resumen)

  1. Pablo abre /. Ve tile de nave a sangre + 3 datos (en taller / listas / esperan) + 4 bicis. PIN-2702 LISTA; PIN-2704 ESPERA. [H1]
  2. Toca Encargo → /encargo. Elige Frenos. [H2]
  3. Paso 2: escribe «Pablo Mora», teléfono, color del cuadro. POST → /ok/PIN-XXXX. Lee las cuatro oposiciones.
  4. Nuria entra a /login/mesa. Ganchos por estado + encargos.
  5. Lee PIN-2702 LISTA y el encargo nuevo de Pablo en ESPERA. Copy: recoger no es alquilar.

Backstage: Nest + Neon + JWT. Repartidor y dueño no entran. No hay Decathlon. No hay GPS.

8. Blueprint (resumen)

CapaQué pasa
Frontstage (nave / calle)Bento Deriva en móvil. Configurador. Form dejar bici. Success. S-TOP.
Backstage (mostrador)Nuria mira /mesa. El arreglo físico es oficio, no un lineal. GPS y caja de tienda están fuera de app.
SoporteNest · Neon dedicado PIÑÓN · JWT MECÁNICO · Paper industrial

9. Matriz hallazgo → requisito → feature

Hallazgo (etiquetado)RequisitoFeature v1
[HIPÓTESIS H1] Bento de ganchos reduce WhatsApp4 bicis + 3 métricas en fold sobre tile/ H-BENTO Deriva
[HIPÓTESIS H2] Job explícito evita «lo que sea»Configurador de 4 arreglos/encargo paso 1
[HIPÓTESIS H3] Cuatro bicis bastanSin linealSeed 4 · no Decathlon
[SUPUESTO S2] Sin cuenta de vecinoPOST públicoPOST /api/encargos
[SUPUESTO S3] Una mecánicaUn rol JWTMECANICO
[DECISIÓN S4] Sin e-commerce / GPS / chat / kanbanNo pago, no tracking, no hilo, no columnasFuera de alcance · L3 GPS/e-commerce

10. Preguntas que este case no responde

  • ¿Cuántas bicis reales se dejan en Legazpi en 2026?
  • ¿Qué taller opera un acuerdo con Orbea?
  • ¿Pablo preferiría el WhatsApp?
  • ¿Amparo necesita un modo tipográfico mayor permanente?
  • ¿Nuria marcaría LISTA antes de las 19:00 de verdad?

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

11. Cierre

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

03-information-architecture.md

03 — Arquitectura de información — PIÑÓN

1. Principios de IA

PrincipioAplicación
Bento firstLa home es tile de nave a sangre + 3 datos + 4 bicis. No hay landing de marca por delante. No hay feed. No hay mesa de datos.
Público / mesaPablo deja la bici sin cuenta; Nuria entra con JWT
Configurar → dejar → successProfundidad 2 desde el taller hasta el código (F-CMP)
El núcleo es el configuradorF-CMP: arreglo (rueda / frenos / cadena / revisión) antes de los datos personales
Mesa MECÁNICO = ganchosESPERA / EN_TALLER / LISTA en una mesa; no kanban, no split lista | ficha
Lenguaje de dominioBici, gancho, encargo, taller, mesa — no «SKU», «cita», «sesión», «ejemplar»
Dejar no es comprarEl success no tiene precio ni lineal
Taller no es DecathlonNo hay talla, no hay carrito, no hay stock de venta
Chrome de oficioS-TOP Taller · Encargo · Mesa; bento sin dock de cineclub

2. Sitemap

/                                      Taller bento público (Deriva)                   H-BENTO
/encargo                               Configurador + dejar bici                       F-CMP · público
/ok/:code                              Success post-encargo                            público
/login                                 Login JWT MECÁNICO                              público
/mesa                                  Ganchos ESPERA / EN_TALLER / LISTA              auth
/**                                    → redirect /

Árbol por audiencia

AudienciaNodos relevantes
VECINOTaller → Encargo (configurar → dejar) → Ok. No ve /mesa
MECÁNICOLogin → Mesa · (puede leer el taller y el configurador)
VECINA MAYORTaller / Encargo públicos; sin login

[COMPROBADO] Cinco rutas del encargo L2. No se inventan /buscar, /sesion, /pedir, /lomo, /cita, /tienda, /gps.

El configurador es ruta (/encargo): F-CMP necesita URL compartible y un paso antes del POST. [DECISIÓN]
Dejar bici no es ruta extra: es el paso 2 de /encargo (UI-03). L2 compacto. [DECISIÓN]
/ok/:code usa el código de bici (PIN-2705), no un código de petición distinto. [DECISIÓN]
No hay /buscar: no hay S-CMD. El hallazgo es el bento. [DECISIÓN]
No hay /bici/:code de ficha pública: el oficio de estado vive en el bento y en la mesa. Could L3. [DECISIÓN]

3. Navegación

Top (S-TOP · todas las superficies salvo login/ok pueden mostrarlo)

SlotDestinoVisibilidadNotas
Taller/TodosVuelve al bento Deriva. No es hero de marca
Encargo/encargoTodosEntra al configurador (paso 1)
Mesa/mesaMECÁNICO; si guest → /login?next=/mesaOficio JWT

[DECISIÓN] El top es la navegación primaria. No hay dock (BOBINA), no hay comando (LOMO), no hay rail (ONDA), no hay bottom tabs (MATIZ), no hay wizard chrome (ZAGUÁN).

Desktop ≥960px: barra superior fija grafito; wordmark PIÑÓN a la izquierda; slots a la derecha.
Mobile ~390px: top compacto Taller · Encargo · Mesa; no hamburger. [DECISIÓN] En 390 el top no se esconde detrás de un menú.

Taller público (H-BENTO Deriva)

ElementoDestinoNotas
Tile de nave a sangre≥40 % del recorte 16/10; foto-led
Wordmark PIÑÓN/Sello mark sobre grafito
Eslogan«El gancho, no el lineal.»
3 datosEn taller / Listas / Esperan (números del seed)
Tile de bicicontexto; no ficha4 bicis; modelo, color, job, estado
CTA Encargo/encargoArranque de F-CMP
Slot Mesa (mute)/login o /mesa si hay tokenOficio, no CTA de marca

[DECISIÓN] El taller no tiene tabs de marketing, no tiene «Tienda / Clases / Alquiler». El bento basta para hallar.

Chrome de encargo (F-CMP)

SlotDestinoNotas
← Taller/Un paso atrás, no stepper de 5
Paso 1 Configurar/encargo4 opciones de arreglo; una activa
Paso 2 Dejar/encargo (mismo path, paso 2)Nombre, teléfono, color del cuadro
EnviarPOST → /ok/:codeUna acción

[DECISIÓN] El paso 2 no se alcanza sin job elegido. No hay wizard de criterios tipo ZAGUÁN (zona / presupuesto / musts). Hay dos gestos de oficio: qué se arregla, quién deja la bici.

Chrome de mesa (/mesa autenticado)

SlotDestinoVisibilidadNotas
Mesa/mesaAuthTitular de oficio
GanchosAuthAgrupados ESPERA / EN_TALLER / LISTA
EncargosAuthNombre + teléfono + código; no columnas de flujo
Taller/AuthSecundario vía S-TOP
Salirlimpia token → /AuthCabecera de mesa, no cuarto slot del top

[DECISIÓN] No hay S-SPLIT (RAMAL). No hay kanban (PREGÓN). No hay /mesa/:code: L2 lee ganchos + encargos. ENTREGADA no se lista en mesa v1.

4. Etiquetas de IA (UI)

ConceptoLabel
HomeTaller (no «Inicio», no «Cartelera», no «Hoy», no «Galería»)
FlujoEncargo (no «cita», no «pedido de tienda», no «reserva»)
Form paso 1Qué se arregla
Form paso 2Dejar la bici
SuccessDejada / código
StaffMesa (no «Backoffice», no «Kanban», no «Hoy» JWT)
AuthMecánica (no «Área cliente», no «Programadora»)
CTADejar la bici (no «Comprar», no «Reservar clase», no «Alquilar»)

En docs puede decirse «taller bento» para H-BENTO y «mesa MECÁNICO» para el oficio JWT. En UI pública el titular es Taller. En UI autenticada el titular es Mesa. [DECISIÓN]

5. Contenido de cada nodo de IA

RutaQué hayQué no hay
/Tile de nave, eslogan, 3 métricas, 4 tiles de bici, S-TOPPrecios, login de vecino, talla, GPS, feed de noches
/encargo paso 14 opciones de arreglo, lead, copy irrenunciableCarrito, SKU, «lo que sea» libre
/encargo paso 2Nombre, teléfono, color, job en solo lecturaDNI, email, pago, socio, modelo obligatorio
/ok/:codeCódigo + 4 oposicionesContrato, ticket, «ya está inscrito», QR de tienda
/loginEmail / clave MECÁNICOSignup de vecino
/mesaGanchos de 4 + encargosColumnas Recibido / En curso; split ficha; mapa GPS

6. Error / empty / loading (sitio)

Viven en las mismas rutas, no en URLs extra. Artboards: UI-07 empty · UI-08 error · UI-09 loading.

EstadoSuperficie
LoadingSkeletons de tile + 3 datos + 4 bicis / pasos de encargo / lista de mesa
Empty taller«Aún no hay ganchos.»
Empty mesa«No hay encargos.» (pueden existir 0 requests con 4 bicis seed)
Error red«La red no responde» + Reintentar
404 código«Ese encargo no está» en success
Encargo sin jobCTA Dejar disabled · «Elige qué se arregla.»

7. Profundidad y hallazgo

No hay búsqueda Must: el hallazgo es el bento de 4 bicis. Introducir /buscar copiaría LOMO y rompería la terna. [DECISIÓN]
Nuria no filtra la mesa con chips en v1: ve los tres grupos de ganchos. Could L3: filtro; no se cuela como deuda del L2.

8. Códigos y URLs

PiezaForma
Bici / encargoPIN-2701PIN-2704 (PIN versales, guion, 4 dígitos)
Encargo nuevoPIN-2705+ secuencial al POST
Configurador/encargo
Success/ok/PIN-2705

9. Mapa Paper → rutas

ArtboardRutaComponente
UI-01 Home bento/TallerPage
UI-11 Mobile bento/ @390TallerPage
UI-02 Configurador/encargo paso 1EncargoPage
UI-03 Dejar bici/encargo paso 2EncargoPage
UI-12 Mobile encargo/encargo @390EncargoPage
UI-04 Success/ok/:codeOkPage
UI-05 Login/loginLoginPage
UI-06 Mesa/mesaMesaPage
UI-07 Emptymismas rutasestados
UI-08 Errormismas rutasestados
UI-09 Loadingmismas rutasestados
UI-10 TokensthemeTailwind

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

04-user-flows.md

04 — Flujos de usuario — PIÑÓN

1. Convenciones

TokenSignificado
F-CMPConfigurar el arreglo y luego dejar la bici; la home no es el form
MesaGanchos MECÁNICO, JWT
201Encargo creado (bici ESPERA + request)
400Job ausente / nombre / teléfono / color inválidos
401Mesa sin token
404Código inexistente

2. F1 — Vecino deja la bici desde el bento (Must)

/  →  GET /api/bicis
   →  ve 3 métricas (en taller / listas / esperan) + 4 bicis
   →  tap Encargo  →  /encargo
   →  elige job «Frenos»          (UI-02)
   →  continúa a dejar bici       (UI-03)
   →  escribe nombre «Pablo Mora», teléfono, color «verde»
   →  POST /api/encargos  { name, phone, color, job }
   →  201 { code: PIN-2705, model?, color, job, status: ESPERA }
   →  /ok/PIN-2705

Entrada: taller bento, sin cuenta.
Salida: código visible + copy «dejar la bici ≠ comprar el taller».
Errores: red (reintentar), 400 validación, 0 bicis (empty del taller; el encargo sigue permitido).

AC

  • El form no pide email, DNI, pago ni signup.
  • POST no cobra, no crea user, no abre lineal, no mueve kanban, no enciende GPS.
  • /ok/PIN-2705 muestra las cuatro oposiciones.
  • El paso configurador existe: F-CMP no es un POST oculto en el tile. [DECISIÓN]
  • El paso dejar bici existe en la misma ruta: no es un modal efímero sin URL. [DECISIÓN]
  • Job es uno de rueda / frenos / cadena / revisión. [DECISIÓN]

3. F2 — Vecino intenta enviar sin configurar (Must · estado)

/encargo  →  tap Dejar la bici sin job
          →  CTA disabled o 400 local
          →  copy «Elige qué se arregla.»

AC

  • No se permite POST sin job (400 si se fuerza).
  • Copy: no «arréglame lo que sea». No «añadir al carrito».
  • Pablo puede elegir Frenos y continuar.

4. F3 — Mecánica entra a mesa (Must)

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

AC

  • Sin token, /mesa redirige a /login?next=/mesa.
  • GET /api/mesa sin Bearer → 401.
  • Ganchos: 4 filas agrupadas ESPERA / EN_TALLER / LISTA + encargos (nombre, teléfono, código). No columnas Recibido / En curso.
  • Desktop: grupos + encargos en el panel. 390: apilado bajo el S-TOP.
  • ENTREGADA no aparece. [DECISIÓN]

5. F4 — Estados de sistema

EstadoTriggerUI
Loading tallerGET bicis en vueloSkeletons de tile + 3 datos + 4 tiles (UI-09)
Empty taller200 { bicis: [] }«Aún no hay ganchos.» (UI-07)
Error taller5xx / redReintentar (UI-08)
Loading encargoForm listo; submit pending (UI-09)
Encargo sin jobpaso 2 forzado«Elige qué se arregla.»
Loading mesaGET mesa en vueloSkeletons de gancho + encargos
Empty mesa encargos200 { requests: [] }«No hay encargos.» (los 4 ganchos seed pueden existir)
Login 401credenciales«Email o contraseña no valen.»
404 successcódigo inexistente«Ese encargo no está.»

6. Flujos que no existen

FlujoPor qué
Signup vecinoS2 · Dejar ≠ socio
Comprar bici / linealS4 · Dejar ≠ comprar el taller
Cita de fitness / slotEncargo ≠ cita · ≠ VOLTA
Alquilar / desbloquearRecoger ≠ alquilar
GPS / ruta / última milla≠ TROCHA · S4
Chat≠ PREGÓN
Pedir butaca≠ BOBINA
Pedir mesa de lomo / comando≠ LOMO
Editor de gramos≠ MATIZ
Wizard 1—2—3 de criteriosF-CMP de arreglo, no de finca
Login AmparoSlice L2 · docs / a11y
PATCH estado de biciNuria lee ganchos; no mueve columnas en v1
Catálogo DecathlonH3 · S4
Búsqueda ?q=Sin S-CMD

7. Tiempos de demo (modelo)

ActorRecorridoTecho
PabloTaller → Encargo → dejar → dejada< 90 s
Pablo (sin job)Encargo → bloqueo → elige Frenos → dejar< 90 s
NuriaLogin → mesa → leer PIN-2702 LISTA< 45 s

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

8. Guión de demo canónico

  1. / — tile de nave a sangre + 3 datos (2 en taller / 1 lista / 1 espera) + 4 bicis. Eslogan. S-TOP.
  2. Lectura rápida: PIN-2701 Orbea EN_TALLER frenos; PIN-2702 BH LISTA revisión; PIN-2703 fold EN_TALLER rueda; PIN-2704 Trek ESPERA cadena.
  3. Encargo — /encargo · elige Frenos.
  4. Dejar la bici — nombre Pablo Mora · teléfono · color verde.
  5. Enviar — /ok/PIN-2705. Copy ×4.
  6. /loginnuria@pinon.taller / password123.
  7. /mesa — ganchos ESPERA / EN_TALLER / LISTA; PIN-2702 LISTA; encargo de Pablo en ESPERA si se hizo el POST.
  8. 390: bento + S-TOP; no carousel; targets ≥44px.
  9. API down: error + Reintentar.

9. Contratos de error de API (flujo)

CasoHTTPUI
POST encargo, job ausente / inválido400«Elige qué se arregla.»
POST encargo, nombre vacío400«Escribe un nombre.»
POST encargo, teléfono vacío / corto400«Escribe un teléfono.»
POST encargo, color vacío400«Di el color del cuadro.»
POST encargo, redmark + Reintentar; no navega a ok
GET mesa sin JWT401redirect login
Login malo401copy de login
GET /ok code 404404«Ese encargo no está.»

10. S-TOP en flujo

DesdeSlot EncargoComportamiento
/Encargo/encargo paso 1
/encargo paso 1Encargoaria-current
/encargo paso 2Encargoaria-current; atrás vuelve a paso 1
/ok/:codeTallerVuelve al bento
/ guestMesa/login?next=/mesa
/ con tokenMesa/mesa

[DECISIÓN] El slot Encargo no inventa un quinto SKU; abre el configurador vacío (job aún no elegido).

05-data-model.md

05 — Modelo de datos — PIÑÓN

1. Visión general

Dominio L2 de ganchos de taller + configurador de arreglo + encargo autenticable:

EntidadTabla SQLPropósito
UserusersIdentidad de oficio (rol MECANICO)
SessionsessionsSesión JWT / token persistido
BikebicisCuadro en gancho (código PIN-XXXX, modelo, color, job, estado, cover)
RequestrequestsEncargo anónimo de cuenta sobre una bici (nombre, teléfono)

Base: PostgreSQL (Neon project dedicado PIÑÓN · DATABASE_URL) · IDs: serial + texto estable (PIN-2701).
[DECISIÓN] ensureSchema es válido si el contrato de tablas se cumple; el brief de stack no exige Prisma.

Contrato de producto: bicis + requests + JWT MECANICO.
No sesiones / pedidos / ejemplares / programas / nodes / altas / bookings.

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

Role

ValorDescripción
MECANICOMecánica de la mesa; único rol autenticado v1

JobPart

ValorLabel UIDescripción
RUEDARuedaPinchazo, radio, cubo
FRENOSFrenosZapatas, disco, líquido
CADENACadenaCadena, piñón, tensado
REVISIONRevisiónPase general, no «lo que sea»

[DECISIÓN] Un encargo lleva un job. Multi-pieza y «arréglame todo» quedan fuera (H2).

BiciStatus

ValorDescripción
ESPERAColgada, aún no se trabaja
EN_TALLEREn el gancho de trabajo
LISTASe puede recoger
ENTREGADAYa no cuelga; fuera de la mesa v1

Un POST de encargo siempre crea la bici en ESPERA. [DECISIÓN]
Nuria no hace PATCH de estado en v1: la mesa es lectura de ganchos. [DECISIÓN]

3. Diagrama ER (texto)

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

sessions
  id, user_id → users
  expires_at, revoked_at
  created_at

bicis
  id
  code (unique, PIN-XXXX)
  model, color
  job (RUEDA|FRENOS|CADENA|REVISION)
  status (ESPERA|EN_TALLER|LISTA|ENTREGADA)
  cover
  sort_order
  created_at, updated_at
  1 ──< requests

requests
  id
  bici_id → bicis
  code (denorm PIN-XXXX)
  name
  phone
  created_at

v1: una sola MECÁNICO opera sobre el conjunto global.
No hay FK de vecino-usuario: el vecino no se loguea.
requests.name es el nombre de mostrador (oral), no una cuenta.
requests.phone es el recado para avisar que está LISTA; no se pinta en el bento público.

4. Tablas

users

ColumnaTipoNotas
idBIGSERIAL PK
emailTEXT UNIQUEnuria@pinon.taller
password_hashTEXTbcrypt 12 · seed $2b$12$OEKcNck63neDJ.CrVP0lNOaXp2NG2zd2aMiGmnYY221h4ZAZ58x1m
nameTEXTNuria Vega
roleTEXTMECANICO
created_atTIMESTAMPTZ

sessions

ColumnaTipoNotas
idUUID PKsid del JWT
user_idBIGINT FK
expires_atTIMESTAMPTZ
revoked_atTIMESTAMPTZlogout
created_atTIMESTAMPTZ

bicis

ColumnaTipoNotas
idBIGSERIAL PK
codeTEXT UNIQUEPIN-2701
modelTEXTOrbea urbana · BH paseo · Classic fold · Trek niño · o «bici» si el POST no trae modelo
colorTEXTverde / crema / negra / azul / el del form
jobTEXTRUEDA | FRENOS | CADENA | REVISION
statusTEXTESPERA | EN_TALLER | LISTA | ENTREGADA
coverTEXT/assets/bicis/orbea.jpg (seed); POST nuevo puede ir sin cover
sort_orderINTEGER1 = primer tile del bento
created_at / updated_atTIMESTAMPTZ

requests

ColumnaTipoNotas
idBIGSERIAL PK
bici_idBIGINT FK
codeTEXTDenorm PIN-2701 para mesa sin join extra
nameTEXTNombre de mostrador (Pablo Mora)
phoneTEXTTeléfono de recado
created_atTIMESTAMPTZ

Sin email, sin DNI, sin pago, sin GPS. Dejar la bici ≠ comprar el taller. [DECISIÓN]

Índices: bicis(code), bicis(status), bicis(sort_order), users(email), requests(bici_id), requests(created_at DESC).

5. Seed

MECÁNICO

nuria@pinon.taller / password123 · Nuria Vega · MECANICO
Hash bcrypt fijo: $2b$12$OEKcNck63neDJ.CrVP0lNOaXp2NG2zd2aMiGmnYY221h4ZAZ58x1m

Bicis

codemodelcolorjobstatuscover
PIN-2701Orbea urbanaverdeFRENOSEN_TALLER/assets/bicis/orbea.jpg
PIN-2702BH paseocremaREVISIONLISTA/assets/bicis/bh.jpg
PIN-2703Classic foldnegraRUEDAEN_TALLER/assets/bicis/fold.jpg
PIN-2704Trek niñoazulCADENAESPERA/assets/bicis/trek.jpg

Métricas derivadas del seed: en taller 2 · listas 1 · esperan 1. ENTREGADA = 0.

[SUPUESTO de taller] Modelos, colores y marcas son atrezzo. No es un taller oficial ni un acuerdo con Orbea / BH / Trek.
[DECISIÓN] sort_order 1…4 = PIN-2701…2704.

Requests seed

codenamephone
PIN-2701Elena Ortiz612440271
PIN-2702Luis Castro625118903
PIN-2703Marta Gil633772014
PIN-2704Iván Soto647331890

El POST de smoke crea el de Pablo Mora sobre un código nuevo (PIN-2705).
El seed idempotente restaura las 4 bicis de catálogo (estados y jobs) para que el demo sea repetible. [DECISIÓN]
Re-seed no borra PIN-2705+ salvo flag explícito de demo. [DECISIÓN]

6. JSON (camelCase)

API: sortOrder, createdAt, requestCount, enTaller, listas, esperan, cover, status, model, color, job, code, name, phone.
SQL: sort_order, created_at, request_count derivado.

GET /api/bicis

{
  "metrics": { "enTaller": 2, "listas": 1, "esperan": 1 },
  "bicis": [
    {
      "code": "PIN-2701",
      "model": "Orbea urbana",
      "color": "verde",
      "job": "FRENOS",
      "status": "EN_TALLER",
      "cover": "/assets/bicis/orbea.jpg",
      "sortOrder": 1
    }
  ]
}

Lista pública: no incluye name ni phone de requests (evita enumerar vecinos). [DECISIÓN]
Métricas no cuentan ENTREGADA. [DECISIÓN]

GET /api/bicis/:code

Mismo shape de item; 404 si no existe. El success puede usarlo para pintar modelo/color/job.

POST /api/encargos

Request:

{ "name": "Pablo Mora", "phone": "600123123", "color": "verde", "job": "FRENOS", "model": "urbana" }

model opcional. name obligatorio, trim, min 2. phone obligatorio, dígitos ≥ 9. color obligatorio, trim, min 3. job obligatorio, enum. [DECISIÓN]

Response 201:

{
  "code": "PIN-2705",
  "color": "verde",
  "job": "FRENOS",
  "status": "ESPERA",
  "dejada": true
}

Algoritmo: INSERT bici (status ESPERA, code siguiente) + INSERT request. Transacción única. [DECISIÓN]

GET /api/mesa (JWT)

{
  "metrics": { "enTaller": 2, "listas": 1, "esperan": 1 },
  "ganchos": {
    "ESPERA": [ /* bicis */ ],
    "EN_TALLER": [ /* bicis */ ],
    "LISTA": [ /* bicis */ ]
  },
  "requests": [
    {
      "id": 1,
      "code": "PIN-2701",
      "name": "Elena Ortiz",
      "phone": "612440271",
      "job": "FRENOS",
      "status": "EN_TALLER",
      "createdAt": "2026-08-27T09:12:00.000Z"
    }
  ]
}

7. Reglas de integridad

ReglaDetalle
Unicidad de códigobicis.code UNIQUE
Job enumSi job ∉ {RUEDA,FRENOS,CADENA,REVISION} → 400
Encargo siempre ESPERAPOST no escribe EN_TALLER / LISTA
Sin user en requestNo FK a users desde requests
Mesa privadaGET /api/mesa exige JWT role MECANICO
Bento públicoGET /api/bicis sin auth
Teléfono no públicoGET /api/bicis sin phone ni name
ENTREGADA oculta en mesaganchos solo ESPERA / EN_TALLER / LISTA

8. Fuera del modelo v1

ConceptoPor qué fuera
Precio / pago / SKU / tallaDejar ≠ comprar
Email del vecinoMinimización; S2. El recado es el teléfono
GPS / lat-lng / rutaS4 · L3
Tabla sesiones / pedidosLeftover BOBINA
Tabla ejemplaresLeftover LOMO
PATCH statusMesa de lectura; no kanban
Multi-tenant naveL2 compacto

9. Naming vs leftover

Prohibido (leftover)Contrato PIÑÓN
sesiones / pedidosbicis / requests
PROGRAMADORMECANICO
bobina-apipinon-api
BOB-XXXXPIN-XXXX
ABIERTA / COMPLETAESPERA / EN_TALLER / LISTA / ENTREGADA
ejemplares / BIBLIObicis / MECANICO
puerto 30263027

06-tech-stack.md

06 — Stack técnico — PIÑÓN

1. Resumen

CapaElecciónNotas
FrontendAngular (standalone) + TailwindPuerto 4200
BackendNestJSPuerto 3027 · prefijo /api
DBNeon PostgreSQLProject dedicado PIÑÓN · DATABASE_URL
AuthJWT BearerRol MECANICO
PackagepnpmApps independientes (pnpm --filter)
DiseñoPaperFile 01M110K5JHDQ899C360KC4D0WD
Repo/Users/cristian/orca/pinon-appGH Criscode2022/pinon-app

[COMPROBADO] Angular + NestJS + Neon + Tailwind, puerto API 3027, Paper file ID y path de app salen del encargo.

2. Por qué este stack

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

3. Puertos y health

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

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

4. Estructura de repo (contrato)

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

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

5. Variables de entorno (API)

VariableUso
DATABASE_URLNeon connection string (project PIÑÓN)
JWT_SECRETFirma HS256
PORT3027
NODE_ENVdevelopment / production

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

6. Auth

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

[COMPROBADO] Credenciales demo: nuria@pinon.taller / password123.

7. Endpoints (contrato)

MétodoRutaAuthRespuesta clave
GET/api/healthNopinon-api
GET/api/bicisNometrics + array 4
GET/api/bicis/:codeNoitem
POST/api/encargosNo201 / 400
POST/api/auth/loginNo{ accessToken }
GET/api/mesaJWTganchos + requests

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

8. Frontend — rutas y componentes

RutaComponenteGuard
/TallerPage
/encargoEncargoPage
/ok/:codeOkPage
/loginLoginPage
/mesaMesaPageauthGuard MECANICO

Chrome: TopNavComponent (S-TOP). Tokens Tailwind: ground, cream, card, mark, mute, chrome.

9. Assets

Origen caseDestino app
2026-08-27-pinon/assets/hero.jpgTile Deriva / cover
assets/bicis/*.jpgapps/web/public/assets/bicis/ o equivalente

Covers en DB como paths /assets/bicis/orbea.jpg etc. [DECISIÓN]

10. Calidad y toolchains

HerramientaUso v1
TypeScriptStrict en api y web
ESLint / PrettierSerie daily
Vitest / JestSmoke API del slice
PlaywrightSmoke S01–S12 del plan QA (doc 13)

11. Anti-stack (no introducir)

TecnologíaPor qué no
Prisma obligatorioBrief no lo exige; ensureSchema + pg válido
Stripe / pagoDejar ≠ comprar
Firebase AuthJWT propio MECANICO
GraphQLREST L2
Socket.io / chat≠ PREGÓN
Mapbox / GPS≠ TROCHA · L3
Player video≠ BOBINA / Filmin
OPAC / Absys libs≠ LOMO

12. Criterios de aceptación técnicos

  1. GET /api/healthservice: "pinon-api".
  2. Seed idempotente: 1 MECÁNICO + 4 bicis + 4 requests.
  3. POST encargo crea bici ESPERA + request y devuelve PIN-XXXX.
  4. GET mesa sin token → 401.
  5. Web en 4200 consume API 3027 sin mixed-content local.
  6. 0 referencias de producto a sesiones, PROGRAMADOR, bobina-api en runtime.

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

07-creative-direction.md

07 — Dirección creativa — PIÑÓN

1. Concepto

PIÑÓN es una nave de esmalte y hormigón: se entra a un tile de taller a sangre con tres números y cuatro ganchos, y se sale habiendo dejado una bici, no una landing de «tu bike shop». El ground es grafito. El naranja de reflector puntúa, poco. El cromo marca meta, poco.

Mood elegido: industrial.
Primer instinto descartado: nocturnal / fixie neón (tienda Rapha). Un taller de Legazpi se lee con esmalte, hormigón y naranja de reflector, no con LED de fixie.

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

2. Territorio visual

EjeNo
SuperficieGrafito #2C3033, cream #F3F1EC, card #1A1C1B, mark #E24A17Velvet BOBINA, caliza LOMO, cartel ONDA, hielo RAMAL
TipoSpectral + SoraCormorant+Manrope (BOBINA), Source Serif+Outfit (LOMO), Instrument Serif
FotoNave, gancho, esmalte de cuadro, barrio ArganzuelaLED de fixie, lineal Decathlon, stock Rapha, GPS de furgoneta
GridDeriva: tile nave ≥40 % 16/10 + 3 datos + 4 bicisHero 2-col + 3 cards (AP-12) · feed (BOBINA) · mesa de datos (LOMO)
AcentoMark en CTA/foco/slot activo; cromo en metaBrass de sala, cinta amarilla ONDA, amatista MATIZ
ChromeS-TOP Taller · Encargo · MesaDock cineclub, comando archivo, rail, bottom tabs

3. Paleta

TokenHexRol
Ground / G-GRAPHITE#2C3033Suelo de nave y esmalte de cuadro. Fondo de página.
Cream#F3F1ECTexto primario, ficha legible sobre grafito.
Card#1A1C1BGancho / tarjeta de bici. Superficie elevada.
Mark#E24A17Naranja de reflector: CTA Dejar, foco, wordmark. Poco.
Mute#8B8E8AMeta, labels, job secundario, idle S-TOP
Chrome#C5C8C4Cromo: filetes, idle fino. Poco. No pinta el header.

Jerarquía de color: el grafito carga; el mark puntúa; el cromo filetea. Si el mark pinta fondos enteros, deja de ser reflector y se vuelve «brand naranja Decathlon». El cromo no decora la cabecera: solo puntual (bordes, meta). El texto sobre grafito es cream; nunca mute como párrafo largo. Cream sobre grafito debe pasar contraste WCAG 2.2 AA. [DECISIÓN]

Candidatos de mood descartados: nocturnal/fixie neón (primer instinto taller cool), rusted, arid, botanical.

4. Tipografía

UsoFamiliaTamaños de referencia
WordmarkSpectral 60024–28 desktop · 22 mobile
Titular de taller / mesaSpectral 60032–44
Código PIN-XXXXSpectral 60028–36
Modelo de biciSpectral 60022–28
Cuerpo / disclaimersSora 40016–17 / 26–28 lh
UI, S-TOP, form, listaSora 400/500/60014 / 16
Meta (job, status, color)Sora 50012–13, tracking 0.08em, cream o mute

Prohibido: Spectral por debajo de 18px (se rompe). Sora en el wordmark de taller (se vuelve SaaS). Mark como color de texto de párrafo largo (contraste).

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

5. Fotografía

AssetDebeNo debe
hero.jpgNave de taller: hormigón, ganchos, luz de industrial, barrioLineal Decathlon, LED Rapha, stock Unsplash de fixie neón
orbea.jpgOrbea urbana verde; esmalte, barrioPóster de catálogo 2026 con precio
bh.jpgBH paseo crema; LISTA se lee en UIBanner de gran superficie
fold.jpgClassic fold negra; gancho, ruedaThumbnail de e-commerce
trek.jpgTrek niño azul; ESPERA se lee en UIFoto de club / cita fitness

Alt: modelo + color, no «imagen1». Ver doc 09.

[COMPROBADO] Los cuatro covers y el hero existen en assets/.

6. Registro R-HY

Híbrido: identidad de oficio clásica (S-TOP de taller, wordmark Spectral, ganchos) + bento/configurador (H-BENTO + F-CMP). No es un dashboard de seguros. No es un kiosk de horas. No es una mesa de datos de archivo. No es neón de fixie.

La innovación está en H-BENTO Deriva + S-TOP + F-CMP, no en un look «bike LED». [DECISIÓN]

7. Anti-moods

MoodPor qué no
Neón / nocturnal fixiePrimer instinto; es Rapha / tienda cool
Candlelit / velvetFue BOBINA
Mineral / calizaFue LOMO
Signage / cinta amarillaFue ONDA
Ice institucionalFue RAMAL
Chapel amatistaFue MATIZ
Vehicle dashboardFue TEMPLE / TROCHA
Highlighter fogFue PREGÓN

8. Densidad (AP-21)

En el recorte Deriva: eslogan + tile de nave dominante + 3 datos (en taller / listas / esperan) + 4 tiles con modelo, color, job y estado visibles sin hover. Headline huérfano + foto = card hueca. [COMPROBADO] CRON §5.8 / D-P1-09 foto-led.

Tile de nave ≥40 % del recorte 16/10. Los 3 datos y las 4 bicis no tapan el oficio de la foto: legibles, no sticker. [DECISIÓN]

9. Motion

GestoTratamiento
Entrada bentoFade corto 120–160ms; tile estático (no Ken Burns agresivo)
Hover tile desktopRing mark 2px; sin lift excesivo
S-TOP activoMark en label; idle mute
Reduced motion0ms; tile sin parallax

10. Voice visual ↔ copy

El mood industrial refuerza el microcopy: gancho de nave, no lineal. Si la UI parece Decathlon (precio, talla, naranja de marca a pantalla completa) o Rapha (neón, kit), el copy irrenunciable pierde fuerza. [DECISIÓN]

08-design-system.md

08 — Sistema de diseño — PIÑÓN

1. Tokens

TokenValorUso
--ground#2C3033Fondo de página (grafito de nave)
--cream#F3F1ECTexto primario, títulos
--card#1A1C1BTarjeta de bici, form, mesa
--mark#E24A17CTA, foco, S-TOP activo
--mute#8B8E8AMeta, idle
--chrome#C5C8C4Filetes, cromo puntual
--font-displaySpectralTitulares
--font-sansSoraUI
--target44×44 minToques

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

2. Contraste (obligatorio)

ParUsoNota
Cream #F3F1EC sobre Grafito #2C3033Cuerpo y títulosDebe pasar WCAG 2.2 AA
Cream sobre Card #1A1C1BTexto en tarjetaVerificar AA
Mark sobre GrafitoSolo UI chrome / iconos, no párrafos largosNo sustituye cream
Mute sobre GrafitoMeta corta; no cuerpoEvitar párrafos mute
Chrome sobre GrafitoFilete / meta cortaNo cuerpo

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

3. Escala de tipo

RolSize / leading
Display tallerclamp(2.2rem, 5vw, 3.6rem) / 0.95
H1 mesa / success2.5rem / 1
H2 modelo28px / 32px
Cuerpo16–17 / 26
Meta12–13 / 16, tracking 0.08em
S-TOP12–14 / 16, Sora 500

4. Componentes

Tile de bici (bento)

Cover recorte + modelo Spectral · color · job · status. Toda la tarjeta es el hit de lectura (no abre ficha pública). Orden por sort_order.

Tile Deriva (UI-01)

Imagen de nave a sangre ≥40 % del frame 16/10; gradient grafito→transparente para legibilidad del bento; wordmark + eslogan + 3 datos (en taller / listas / esperan).

Dato (métrica de gancho)

Número cream grande + label mute («en taller», «listas», «esperan»). Tres en fila desktop; wrap en 390. No es un sparkline ni una tabla H-DATA.

Configurador (UI-02)

Cuatro opciones exclusivas: Rueda · Frenos · Cadena · Revisión. Opción activa: ring mark + aria-checked. CTA Continuar (paso 2) disabled sin selección.

Form dejar bici (UI-03)

Nombre, teléfono, color del cuadro, job en solo lectura, disclaimer, submit mark.

Success (UI-04)

Código Spectral enorme + bloque card con job y color + 4 oposiciones en cream/mute.

Gancho de mesa MECÁNICO (UI-06)

Grupos ESPERA / EN_TALLER / LISTA. Fila: código · modelo · color · job · status. Encargos debajo: name · phone · code · hora. Sin acciones PATCH en v1.

Login (UI-05)

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

Top nav (S-TOP)

Tres slots: Taller · Encargo · Mesa. Activo: mark. Idle: mute. Fondo ground. Targets ≥44px.

Skeleton (UI-09)

animate-pulse bg-card. aria-busy.

Error (UI-08)

Titular display + cuerpo cream/mute + Reintentar mark.

Empty (UI-07)

Titular Spectral + mute. Sin CTA de Decathlon ni de cita.

Sello ESPERA / EN_TALLER / LISTA

Texto «Espera» / «En taller» / «Lista» + mark o mute. Nunca solo el color. Poco: un sello por tile, no un header naranja.

5. Layouts

SuperficieGrid
Taller 1440Tile nave full-bleed 16/10; 3 datos en fila; 4 tiles 2×2; S-TOP
Taller 390Tile + 3 datos wrap + stack de 4; S-TOP fijo superior
Encargo / Ok / loginColumna max-w-lg
Mesa MECÁNICOGrupos + encargos; stacked < lg

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

6. Estados de control

EstadoTratamiento
DefaultCard + cream
HoverRing mark 2px
Focus visibleOutline mark 2px offset 2
Active / pressedMark fill breve
DisabledOpacity 0.45 · no hit · aria-disabled
Pendingdisabled + aria-busy
ErrorBorde mark + mensaje
Job seleccionadoRing mark + check visible en texto

7. Iconografía

S-TOP: pictogramas simples (nave / llave / mesa). Stroke 1.5–2px. No icon packs «carrito» ni «bici de share». [DECISIÓN]

8. Elevación y bordes

SuperficieTratamiento
Card sobre grafitoSin sombra dura; borde 1px chrome/20 o mute/20
S-TOPBarra ground; filete chrome 1px inferior; no material neón
Modal (si hubiera)No en v1 Must

9. Mapa a Paper UI

UIComponentes clave
UI-01 / 11Tile nave + 3 datos + 4 bicis + S-TOP
UI-02Configurador 4 opciones
UI-03Form dejar bici
UI-04Success
UI-05Login
UI-06Mesa ganchos
UI-07Empty
UI-08Error
UI-09Loading
UI-10Tokens
UI-12Encargo 390

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

09-content-guide.md

09 — Guía de contenido — PIÑÓN

1. Voz

PIÑÓN habla como taller de nave, no como lineal ni como club de fitness.

EjeNo
TonoSeco, breve, de barrioCorporativo Decathlon, hype de bici nueva
Persona«Dejamos la bici» / tuteo de mostrador«Adquiere tu cuadro» / «reserva tu clase»
RitmoFrases cortas. Una idea por línea en disclaimersPárrafos legales de gran superficie
HumorSeco, pocoMemes, jerga de fixie

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

2. Microcopy irrenunciable

Presente en taller (pie o banner), encargo, success y pie de mesa:

OposiciónCopy canónico
Dejar vs comprarDejar la bici ≠ comprar el taller.
Encargo vs citaEncargo ≠ cita de fitness.
Recoger vs alquilarRecoger ≠ alquilar.
Barrio vs gran superficiePIÑÓN no es Decathlon.

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

3. Glosario UI

ConceptoLabel canónicoEvitar
HomeTallerInicio, Cartelera, Hoy, Galería, Catálogo
ItemBici / GanchoSKU, unidad, sesión, ejemplar
FlujoEncargoCita, reserva, pedido de tienda
CTA paso 1ContinuarAñadir al carrito, Reservar
CTA paso 2Dejar la biciComprar, Alquilar, Reservar clase
SuccessDejadaConfirmación de compra, Ticket listo
StaffMesaBackoffice, Admin, Kanban
EstadoEspera / En taller / ListaDisponible / Agotado (retail), En ruta (TROCHA)
Persona authMecánicaProgramadora, Coach, Admin
ArregloRueda / Frenos / Cadena / RevisiónPack, SKU, «lo que sea»

4. Pantalla a pantalla

Taller /

SlotCopy
WordmarkPIÑÓN
EsloganEl gancho, no el lineal.
Dato 1{n} en taller
Dato 2{n} listas
Dato 3{n} esperan
CTAEncargo
EmptyAún no hay ganchos.
ErrorLa red no responde. · Reintentar

Encargo /encargo paso 1 (UI-02)

SlotCopy
TítuloQué se arregla
OpcionesRueda · Frenos · Cadena · Revisión
CTAContinuar
DisabledElige qué se arregla.
AvisoDejar la bici ≠ comprar el taller.

Encargo /encargo paso 2 (UI-03)

SlotCopy
TítuloDejar la bici
Label nombreTu nombre
Label teléfonoTeléfono
Label colorColor del cuadro
Job (solo lectura)Arreglo: {job}
SubmitDejar la bici
DisclaimerNo es una compra. No hay cita. Recoger ≠ alquilar.
Error nombreEscribe un nombre.
Error teléfonoEscribe un teléfono.
Error colorDi el color del cuadro.

Success /ok/:code

SlotCopy
TitularDejada.
Código{code}
CuerpoEncargo de {job} · cuadro {color}. En espera en el gancho.
OposicionesLas cuatro líneas irrenunciables
VolverVolver al taller

Login /login

SlotCopy
TítuloMesa
AyudaSolo mecánica.
Demonuria@pinon.taller
ErrorEmail o contraseña no valen.

Mesa /mesa

SlotCopy
TítuloMesa
GruposEspera · En taller · Lista
Empty encargosNo hay encargos.
SalirSalir
PieDejar la bici ≠ comprar el taller.

5. Alt text de imágenes

AssetAlt (modelo)
heroNave de taller de bicis, ganchos y hormigón, luz industrial
orbeaOrbea urbana verde en gancho
bhBH paseo crema lista para recoger
foldClassic fold negra, arreglo de rueda
trekTrek de niño azul en espera

Evitar «imagen1», «bike.jpg», copy de catálogo con precio. [DECISIÓN]

6. Modelos seed (atrezzo)

Orbea / BH / Classic / Trek son catálogo demo. En UI no se afirma «distribuidor oficial». Los blurbs pueden recordar dejar ≠ comprar. [SUPUESTO de taller]

7. Tono de error

CasoCopy
RedLa red no responde.
404Ese encargo no está.
400 jobElige qué se arregla.
401 mesaEntra como mecánica.

Sin culpa al usuario. Sin jerga HTTP en UI.

8. Anti-copy (vetado)

VetadoPor qué
Comprar / carrito / talla / SKU / precioDecathlon
Reservar clase / plaza / coachVOLTA / fitness
Alquilar / desbloquear / minutosBike-share
En ruta / GPS / paradaTROCHA
Pedir butaca / sesión / taquillaBOBINA
Pedir mesa / lomo / signaturaLOMO
Recibido / En curso / CerradoPREGÓN kanban
«El 80% de vecinos…»Estadística inventada
Arréglame lo que seaRompe H2

9. Criterios de aceptación de contenido

  1. Las cuatro oposiciones aparecen al menos en success y en una superficie de taller o encargo.
  2. Ningún CTA dice Comprar / Alquilar / Reservar clase.
  3. LISTA se etiqueta «Lista», no «Disponible» retail.
  4. Códigos se muestran como PIN-XXXX en versales.
  5. Docs y UI no inventan KPIs numéricos de Legazpi como hecho.

10-accessibility.md

10 — Accesibilidad — PIÑÓN

1. Objetivo

Cumplir WCAG 2.2 AA en el vertical slice L2. Ground oscuro (grafito): el par cream sobre grafito es el contrato de legibilidad. Amparo Díaz (71) es persona de diseño que fuerza contraste, tamaño y targets; no tiene login. [COMPROBADO] requisito del encargo · [DECISIÓN] persona Amparo en docs.

2. Contraste

ParRatio objetivoUso
#F3F1EC sobre #2C3033≥ 4.5:1 (texto) / ≥ 3:1 (UI grande)Cuerpo, títulos
#F3F1EC sobre #1A1C1B≥ 4.5:1Texto en card
#E24A17 sobre #2C3033≥ 3:1 para UI no textoFoco, iconos; no párrafos
#8B8E8A sobre #2C3033Verificar; limitar a meta cortaLabels
#C5C8C4 sobre #2C3033Meta / filete; no cuerpoCromo

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

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

3. Tipografía y lectura

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

4. Targets y pointer

ElementoMínimo
Slots S-TOP44×44 CSS px
CTA Dejar la bici / Continuar≥ 44 px alto
Opción de arregloHit area completa ≥ 44 alto
Tile de biciLectura; no es el único camino al encargo
Inputs≥ 44 alto

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

5. Teclado y foco

SuperficieComportamiento
TallerTab por S-TOP → Encargo
ConfiguradorTab por 4 opciones → Continuar
Form dejarNombre → teléfono → color → submit
LoginEmail → password → entrar
MesaGrupos legibles; salir alcanzable
Focus visibleOutline mark 2px offset 2
Skip link«Saltar al taller» en / si el tile decorativo es largo

Sin keyboard traps. Esc no es obligatorio en v1 (sin modales Must).
Opciones de job: radiogroup + radio o botones con aria-pressed. [DECISIÓN]

6. Semántica y nombres

UIRol / nombre
S-TOPnavigation · aria-label «PIÑÓN»
Slot activoaria-current="page"
3 datoslist o group «Ganchos» · cada dato con texto «{n} en taller» no solo el número
Tiles biciarticle «{model} {color}» + status en texto
Jobradiogroup «Qué se arregla»
Formlabel asociado; errores con aria-live="polite"
Loadingaria-busy="true" en región
Success códigoTexto real, no solo imagen

7. Imágenes y tile

CasoTratamiento
Tile Derivaalt descriptivo corto o alt="" si puro decorativo y el bento encima lleva el oficio
Covers biciAlt «{model} {color}»
Iconos S-TOParia-hidden si hay label texto visible

[DECISIÓN] Preferir tile con alt útil en cover UX; en producto, si el overlay ya nombra PIÑÓN y los ganchos, evitar alt redundante largo.

8. Motion

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

9. Estados y color

ESPERA / EN_TALLER / LISTA / error nunca se comunican solo con color: texto + sello. Mark refuerza, no sustituye. [DECISIÓN]

10. Auth y a11y

  • Login solo MECÁNICO; Amparo no necesita cuenta para leer el taller ni dejar bici.
  • Mensajes de error de login claros, sin enumerar si el email existe (seguridad + claridad).
  • /mesa redirige a login con foco en email.

11. Mobile 390

  • S-TOP fijo no tapa el CTA final: padding-top del contenido ≥ altura top; en encargo, el submit queda por encima del teclado.
  • Formularios: autocomplete name on; tel tel; password current-password.
  • Viewport meta; sin zoom bloqueado. [DECISIÓN]
  • UI-11 bento y UI-12 encargo cubren el recorte 390. No carousel.

12. Criterios de aceptación a11y

  1. Cream sobre grafito usado en cuerpo; mute limitado a meta.
  2. Targets S-TOP y CTA ≥ 44×44.
  3. Focus visible mark en todos los interactivos.
  4. Status y métricas con texto, no solo color o número huérfano.
  5. Reduced motion respetado.
  6. Form con labels y errores anunciables.
  7. Ningún toast único sin pantalla como único success (hay /ok/:code).

13. Fuera de v1 (L3, no deuda)

  • Modo tipográfico «letra grande» persistente para Amparo.
  • App nativa con VoiceOver de taller físico.
  • ATAG de CMS (no hay CMS).

11-privacy-security.md

11 — Privacidad y seguridad — PIÑÓN

1. Principios

PrincipioAplicación v1
MinimizaciónRequest = nombre + teléfono; sin email, DNI, GPS
Separación público / oficioBento y POST encargo públicos; mesa JWT
Sin cuenta de vecinoPablo y Amparo no se registran
Transparencia de copySuccess dice que no es compra ni alquiler
Secretos fuera del repoDATABASE_URL, JWT_SECRET en env

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

2. Datos tratados

DatoDóndeBase operativa (modelo)Retención v1
Nombre de encargorequests.namePrestación del taller (apuntar quién deja)Mientras el seed/demo viva; sin política de mercado afirmada
Teléfonorequests.phoneRecado cuando está LISTAIgual
Color / job / modelobicisOficio del ganchoIgual
Email MECÁNICOusers.emailCuenta de oficioCuenta demo
Password hashusers.password_hashAuthbcrypt 12
JWT sidsessionsSesión de mesaExpiración + revoke

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

[SUPUESTO] El taller demo opera en España; el slice no implementa un RGPD completo de empresa real.

3. Superficies públicas vs privadas

SuperficiePúblicoPrivado
GET /api/bicisSí · sin nombres ni teléfonos
GET /api/bicis/:codeSí · sin teléfono
POST encargosSí · crea request
GET /api/mesaNo · 401Sí · requests con name + phone
Bento UISin listar quién dejó
Mesa UILista encargos

[DECISIÓN] Enumerar teléfonos en el bento rompería privacidad de nave; solo Nuria ve recados.

4. AuthN / AuthZ

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

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

5. Amenazas y mitigaciones L2

AmenazaMitigación
POST encargo spamJob enum + validación teléfono; L3 rate-limit (no es hueco del slice)
Enumeración de teléfonosNo en API pública
JWT robadoExpiración corta + logout; HTTPS en prod
IDOR mesaGuard JWT; sin IDs de request públicos
XSSAngular escaping; no innerHTML de name/phone
SQLiParámetros prepared / query builder
Leftover ADMIN / PROGRAMADORUn solo rol MECANICO

6. Contenido de teléfono y nombre

phone es recado, no tracking. Se muestra a Nuria en mesa. Formato: dígitos, min 9. [DECISIÓN]
No se pide dirección, salud ni datos de terceros sensibles en el form.
name es texto libre corto (min 2, max 80).

7. Cookies y tracking

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

8. Logs

Qué síQué no
Errores de API sin PIIPasswords, JWT completos
code de bici en logs de encargoTeléfono completo en logs públicos

9. Criterios de aceptación

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

10. Fuera de v1 (L3 / org real, no deuda)

DPO, ROPA formal, exportaciones ARCO automatizadas, SSO, 2FA, WAF, geolocalización. Roadmap L3 si el taller deja de ser demo (GPS, e-commerce).

12-analytics.md

12 — Analytics y métricas — PIÑÓN

1. Norte

TipoMétricaDefinición
North Star% de bicis LISTA recogidas sin un WhatsApp de «¿está lista?»Oficio de gancho: el vecino ve el estado (o lo asume por el código) sin recado

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

2. Por qué esta north star

Alternativa descartadaPor qué no
Pageviews de /Vanidad; no mide gancho
Ingresos de linealDejar ≠ comprar; no hay e-commerce
% de clases reservadasEncargo ≠ cita · ≠ VOLTA
% de paradas GPS cerradas≠ TROCHA
% de noches con butaca antes de las 18:00Eso es BOBINA

El WhatsApp de «¿está lista?» es el recado que el bento y la mesa pretenden absorber. [SUPUESTO] operativo de diseño, no dato de campo.

3. Métricas de soporte (modelo)

MétricaDefiniciónHipótesis
Activación vecino1.er POST /api/encargos exitoso por visitanteH2
Tasa taller → encargo//encargoH1
Tasa encargo → POST/encargo → 201H2 copy no frena
Mix de jobsConteo RUEDA / FRENOS / CADENA / REVISIONH2
Integridad auth401 en mesa sin tokenSeguridad
Salud5xx rate APIOps

4. Eventos (contrato si se instrumenta en un L3)

EventoPropsPII
taller_viewmetrics snapshot (conteos)No
encargo_jobjobNo
encargo_submitjobNo nombre, no teléfono
encargo_successcode, jobNo
encargo_invalidhttp:400No
login_successroleNo
mesa_viewNo

[DECISIÓN] Nunca enviar name ni phone a analytics.
Instrumentar eventos no es un hueco del L2: el slice cierra sin tracker. [DECISIÓN]

5. Cálculo north star (modelo)

listas = bicis con status LISTA en la ventana
listas_sin_whatsapp =
  (no medible en v1: no hay canal WhatsApp en producto)
proxy de diseño = visitas a / o /mesa que cubren el estado
                   frente a recados paralelos (cualitativo)

[DECISIÓN] v1 no persiste un flag whatsapp_asked. El north star queda como modelo de oficio, no como SQL fingido.

Timezone: Europe/Madrid. [DECISIÓN]

6. Integridad de expectativa (cualitativa)

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

  • «¿Compro la bici?»
  • «¿Reservo una clase?»
  • «¿Esto es un alquiler?»
  • «¿Es Decathlon?»
  • «¿Dónde está el GPS?»

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

7. Qué no medir en v1

VetadoPor qué
Heatmaps de terceros sin decisiónPrivacidad
Funnel de pagoNo hay pago
DAU de DecathlonNo hay lineal
Estadísticas de Legazpi inventadasÉtica de verdad
Tracking GPSS4 · L3

8. Criterios de aceptación

  1. Docs y UI no muestran un % inventado como hecho.
  2. North star documentada y alineada a H1.
  3. Si hay eventos en un L3, sin PII de requests.
  4. Health y 401 mesa son checks de integridad, no vanidad.

9. Relación con seed

Seed tiene 2 EN_TALLER + 1 LISTA + 1 ESPERA. Un guión con POST sobre un encargo nuevo es el ejemplo narrativo de activación; no es un dato de mercado. [SUPUESTO de demo]

13-qa-test-plan.md

13 — Plan de QA — PIÑÓN

1. Alcance

Smoke y regresión del vertical slice L2: bento, configurador, dejar bici, success, login, mesa, empty/error/loading, mobile 390, contraste cream/grafito.
No incluye campo real de Legazpi ni load test de gran superficie.

2. Entornos

EntornoURLNotas
API localhttp://localhost:3027Neon dedicado PIÑÓN
Web localhttp://localhost:4200Proxy /api
Credencialesnuria@pinon.taller / password123Solo demo

3. Smoke crítico (Must pasar)

IDCasoPasosEsperado
S01HealthGET /api/healthok · service: "pinon-api"
S02BentoGET /api/bicis · abrir /4 bicis · 3 métricas · Deriva visible
S03Métricas seedLeer datos2 en taller · 1 lista · 1 espera
S04Configurador/encargo · sin jobContinuar disabled
S05DejarFrenos + Pablo + teléfono + color · submit201 · /ok/PIN-XXXX
S06Copy successLeer /ok/:code4 oposiciones visibles
S07400Forzar POST sin job400 · mensaje arreglo
S08Login/login NuriaJWT · /mesa
S09Mesa authGET /api/mesa con tokenganchos + requests
S10Mesa 401GET /api/mesa sin token401
S11Mobile/ y /encargo @390S-TOP · 4 bicis · targets
S12SeedTras re-seed2 EN_TALLER · 1 LISTA · 1 ESPERA

4. Regresión funcional

IDÁreaCheck
R01POST crea ESPERANueva bici status ESPERA
R02Request ligadoMesa muestra nombre + teléfono del POST
R03Nombre vacío400 · no navega a ok
R04Teléfono corto400
R05Code inventado/ok/PIN-9999 · 404 UI
R06Guard ruta/mesa sin token → login ?next=
R07LogoutToken limpio · mesa 401
R08S-TOPTaller / Encargo / Mesa navegables
R09Público sin teléfonosJSON bicis sin phone / name
R10Leftover0 bobina-api / sesiones / PROGRAMADOR en UI
R11Job enumPOST job: "LO_QUE_SEA" → 400
R12ENTREGADANo aparece en ganchos de mesa

5. Accesibilidad (muestra)

IDCheck
A01Cream sobre grafito en cuerpo (inspección / contraste)
A02Focus visible mark en tab order
A03S-TOP slots ≥ 44×44
A04Status con texto, no solo color
A05prefers-reduced-motion sin parallax
A06Labels en form dejar y login
A07aria-busy en loading bento
A08Job como radiogroup / aria-pressed

6. Contenido

IDCheck
C01Ningún CTA «Comprar» / «Alquilar» / «Reservar clase»
C02Eslogan en taller
C03LISTA = «Lista» no «Disponible» retail
C04Códigos PIN-XXXX
C05Cuatro oposiciones en success

7. Visual / Paper

IDCheck
V01Tile nave a sangre + 3 datos + 4 bicis (no hero 2-col, no feed)
V02Mood industrial (no neón fixie)
V03Covers seed cargan (orbea/bh/fold/trek)
V04Mesa = ganchos por estado (no kanban de columnas)
V05S-TOP no dock

8. API negativa

CasoHTTP
Login malo401
Encargo sin nombre400
Encargo sin job400
Encargo job inválido400
Encargo code 404 GET404
Mesa sin auth401

9. Datos de prueba

ActorDato
VecinoPablo Mora · 600123123 · color verde · job FRENOS
Bici happy seedPIN-2702 LISTA
Bici espera seedPIN-2704
MECÁNICOnuria@pinon.taller

Tras smoke: re-seed para restaurar las 4 de catálogo. [DECISIÓN]

10. Criterio de salida

Smoke S01–S12 en verde. Sin P0 (health mal, encargo roto, mesa abierta sin auth, copy Decathlon ausente en success).
P1 visual puede quedar anotado; no reabre el alcance L2.

11. Fuera de alcance QA v1

Penetration test, auditoría RGPD formal, GPS, pasarela de pago, compatibilidad IE, métricas reales de north star instrumentadas. Eso es L3 u org real, no un agujero de este slice.

14-dev-handoff.md

14 — Handoff a desarrollo — PIÑÓN

1. Contrato vivo

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

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

2. Definition of Done (DoD) L2

#Criterio
1Rutas / /encargo /ok/:code /login /mesa
2Home = Deriva H-BENTO (tile nave + 3 datos + 4 bicis), no H-FEED ni H-DATA ni hero 2-col
3Chrome S-TOP Taller · Encargo · Mesa
4F-CMP: configurar job y luego dejar bici en /encargo
5POST encargo público; success con 4 oposiciones
6JWT MECÁNICO; mesa 401 sin token
7Seed 4 bicis · 2 EN_TALLER · 1 LISTA · 1 ESPERA
8Health pinon-api · puerto 3027
9Tokens industrial + Spectral/Sora
10Empty / error / loading
11Mobile 390 usable (bento + encargo)
120 dominio sesiones / PROGRAMADOR / bobina-api

El DoD cubre todo el slice. No queda producto in-scope como «siguiente sprint». [DECISIÓN]

3. Mapa Paper → Angular

UIRutaComponente
UI-01 / 11/TallerPage
UI-02 / 03 / 12/encargoEncargoPage
UI-04/ok/:codeOkPage
UI-05/loginLoginPage
UI-06/mesaMesaPage
UI-07 / 08 / 09estadosmismos components
UI-10themeTailwind

4. API checklist

MétodoRutaAuth
GET/api/healthNo
GET/api/bicisNo
GET/api/bicis/:codeNo
POST/api/encargosNo
POST/api/auth/loginNo
GET/api/mesaJWT MECANICO

Body encargo: { name: string, phone: string, color: string, job: JobPart, model?: string }.
INSERT bici ESPERA + request en transacción. [DECISIÓN] ver doc 05.

5. Seed y credenciales

ItemValor
Emailnuria@pinon.taller
Passwordpassword123
Hash$2b$12$OEKcNck63neDJ.CrVP0lNOaXp2NG2zd2aMiGmnYY221h4ZAZ58x1m
CodesPIN-2701…2704
Covers/assets/bicis/{orbea,bh,fold,trek}.jpg

6. Anti-patrones de implementación

No hacerHacer
Puerto 3026 / health bobina-api3027 / pinon-api
Tabla sesiones / pedidosbicis / requests
Dock S-DOCKS-TOP
Feed H-FEEDBento Deriva
Kanban mesaGanchos por estado
Pago / Stripe / catálogoPOST nombre + teléfono + color + job
GPS / MapboxFuera · L3
Hero 2-col marketingDeriva foto-led
Wizard 5 pasosDos pasos F-CMP

7. Assets

Copiar desde case:

  • assets/bicis/orbea.jpg
  • assets/bicis/bh.jpg
  • assets/bicis/fold.jpg
  • assets/bicis/trek.jpg
  • assets/hero.jpg (tile Deriva / cover)

[COMPROBADO] existen en el case.

8. QA mínimo antes de merge

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

9. Open questions (no reabren L2)

PreguntaDefault ya decidido
¿Prisma o pg + ensureSchema?ensureSchema válido
¿localStorage vs memory token?localStorage demo OK
¿Teléfono maxlength?15 dígitos
¿Cover del POST nuevo?Vacío o placeholder; seed sí tiene foto
¿PATCH status?No en v1

10. Contacto de diseño

Paper file + docs 07–09. No reinventar neón fixie. Mood industrial. Ground #2C3033. Mark #E24A17.

15-roadmap.md

15 — Roadmap — PIÑÓN

1. Horizonte

FaseNombreIntención
L2Slice actualBento + configurador + dejar bici + mesa JWT · cerrado en esta iteración
L3Nice-to-have de otro productoSolo GPS y e-commerce, y solo con brief nuevo

[DECISIÓN] El L2 no deja producto ni código in-scope como «próximos pasos». Este roadmap no es un cajón de deuda. Empty, error, loading, mobile, auth, seed, copy y API están en el slice de hoy.

2. Hecho en L2 (Must · cerrado)

PiezaEstado
H-BENTO Deriva 4 bicis + 3 métricasMust · cerrado
F-CMP configurador (rueda / frenos / cadena / revisión)Must · cerrado
Dejar la bici sin cuentaMust · cerrado
Success + 4 oposicionesMust · cerrado
Login MECÁNICOMust · cerrado
Mesa de ganchos ESPERA / EN_TALLER / LISTAMust · cerrado
Empty / error / loading / 390Must · cerrado
Docs 00–20 + README + executiveMust · cerrado
Paper 12 UX + 12 UI (inventario)Must (ref) · cerrado
Contrato pinon-app · API :3027 · health pinon-apiMust · cerrado

Nada de la tabla se reabre como backlog de «el código ya vendrá». El case L2 cierra en una iteración. [DECISIÓN]

3. L3 only (nice-to-have · otro brief)

IDIdeaPor qué L3Riesgo
L3-01GPS de la bici / aviso de llegadaRompe S4; huele a TROCHA (la bici se deja, no se reparte)Flota disfrazada
L3-02E-commerce de recambios o cuadrosRompe «dejar ≠ comprar»; huele a DecathlonLineal el día 2

Estas dos ideas no completan PIÑÓN. Completarían otro producto. [DECISIÓN]

4. Anti-roadmap (no disfrazar)

Pedido típicoRespuesta
«Pon un lineal / precio / talla»No · Dejar la bici ≠ comprar el taller
«Pon GPS»No en L2 · L3-01 con brief nuevo
«Pon cita / clase»No · Encargo ≠ cita de fitness
«Pon alquiler»No · Recoger ≠ alquilar
«Pon búsqueda tipo LOMO»No · rompe terna H-BENTO
«Pon kanban»No · ≠ PREGÓN
«Pon feed de cineclub»No · N−1 ya fue BOBINA
«Empty / loading los dejamos para después»No · están en el L2 de hoy
«El código es el próximo paso del case»No · el contrato L2 está cerrado; no se lista como roadmap de producto

5. Dependencias del slice cerrado

DependenciaNota
Neon dedicado PIÑÓNL2 (DATABASE_URL)
Paper file 01M110K5JHDQ899C360KC4D0WDDiseño; inventario en 00
pinon-app · GH Criscode2022/pinon-appContrato de build (doc 20)

6. Criterios para abrir un L3

  1. Smoke L2 en verde (doc 13).
  2. Copy irrenunciable intacto.
  3. El brief L3 nombra GPS o e-commerce sin reabrir ganchos, F-CMP ni mesa.
  4. North star sigue siendo modelo o se instrumenta sin PII.

7. Cierre

L2 está completo en una iteración. El roadmap es un muro contra el lineal y el GPS, no una lista de lo que «faltó». [DECISIÓN]

16-interaction-specs.md

16 — Especificación de interacción — PIÑÓN

1. Convenciones

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

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


2. Home bento (UI-01) + mobile (UI-11) · H-BENTO Deriva

GestoResultado
Primera cargaLoading (UI-09): skeleton tile + 3 datos + 4 tiles card; aria-busy
200 con 4Tile de nave a sangre + 3 datos + 4 bicis. Modelo, color, job, estado
200 con 0UI-07 empty «Aún no hay ganchos.»
Error 5xx / redUI-08 + Reintentar (repite GET bicis)
Tap Encargo (S-TOP o CTA)/encargo paso 1
Tap Mesa (S-TOP)/login o /mesa si hay token
Hover tile desktopRing 2px mark. Sin lift excesivo

AC: modelo, color, job y estado visibles sin hover. Tile nave ≥40 % del recorte 16/10 (AP-21 / D-P1-09). Tres datos con texto («2 en taller»), no solo cifra. Cero botones Comprar / Alquilar / Reservar clase.

El aviso «PIÑÓN no es Decathlon» es texto, no un CTA de tienda. [DECISIÓN]

390: mismas 4 bicis apiladas. No carousel. S-TOP visible. [DECISIÓN]


3. Configurador (UI-02) + mobile encargo (UI-12) · F-CMP paso 1

GestoResultado
Carga4 opciones; ninguna seleccionada; Continuar disabled
Tap Rueda / Frenos / Cadena / RevisiónSelección exclusiva; ring mark; Continuar enabled
Tap ContinuarPaso 2 en la misma ruta (UI-03)
Tap ← Taller/

AC: una sola pieza. Cero «lo que sea». Cero carrito. Cero wizard de criterios (ZAGUÁN).


4. Dejar bici (UI-03) · F-CMP paso 2

GestoResultado
CargaForm + job en solo lectura + disclaimer
AtrásVuelve a paso 1 conservando el job
Nombre / teléfono / color vacío + submitError de campo · no POST
Submit válidoPOST · pending en botón
201/ok/:code con state
400mark + mensaje de campo
Redseal + Reintentar; no navega a ok

AC: no email, no DNI, no pago. Dejar la bici ≠ comprar el taller visible.


5. Success (UI-04)

GestoResultado
Entrada desde 201Código PIN-XXXX grande + job + color + 4 oposiciones
Tap Volver/
Deep link directoGET /api/bicis/:code; 404 → «Ese encargo no está.»

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


6. Login (UI-05)

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

AC: sin signup. Ayuda demo mute.


7. Mesa MECÁNICO (UI-06)

GestoResultado
Primera cargaLoading skeletons grupos + encargos
200Ganchos ESPERA / EN_TALLER / LISTA + requests (name, phone, code, hora)
Empty encargos«No hay encargos.»
401Redirect login
SalirLimpia token → /
Tap filaSin /mesa/:code en v1; lectura

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


8. S-TOP · chrome

GestoResultado
Tap Taller/
Tap Encargo/encargo paso 1
Tap MesaAuth → /mesa; guest → login
ActivoMark + aria-current
IdleMute

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


9. Empty / Error / Loading (UI-07 / UI-08 / UI-09)

EstadoUI
LoadingPulse card; aria-busy
Empty tallerDisplay + mute + sin CTA de Decathlon
Empty mesa encargosMute
ErrorTitular + Reintentar mark

10. Motion

GestoDefaultReduced
Aparición bentoFade 140msInstant
Hover ring120msInstant
Tile naveEstáticoEstático

Sin Ken Burns agresivo sobre Deriva. [DECISIÓN]


11. Guión de interacción demo

  1. / loading → tile + 3 datos + 4 bicis.
  2. Leer PIN-2702 LISTA / PIN-2704 ESPERA.
  3. Encargo → Frenos → form Pablo → pending → success.
  4. S-TOP Mesa → login → mesa con gancho ESPERA nuevo.
  5. 390: S-TOP no tapa CTA; scroll con padding.

12. Criterios de aceptación de interacción

  1. F-CMP no salta el configurador.
  2. POST sin job no navega a ok.
  3. Pending no doble-envía.
  4. S-TOP siempre alcanzable en 390.
  5. Focus visible en todo el recorrido teclado.

17-prototype-map.md

17 — Mapa de prototipo — PIÑÓN

1. Fuentes

FuenteID / path
Paperhttps://app.paper.design/file/01M110K5JHDQ899C360KC4D0WD
File ID01M110K5JHDQ899C360KC4D0WD
UX-count12
UI-count12
App/Users/cristian/orca/pinon-app
Case assets2026-08-27-pinon/assets/

[COMPROBADO] conteos y file ID en docs/00-paper-reference.md.

2. UX process → docs

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

3. UI producto → rutas / componentes

UINombreRutaComponente Angular
UI-01Home bento/TallerPage
UI-02Configurador/encargo paso 1EncargoPage
UI-03Dejar bici/encargo paso 2EncargoPage
UI-04Success/ok/:codeOkPage
UI-05Login/loginLoginPage
UI-06Mesa/mesaMesaPage
UI-07Emptymismas rutasestados
UI-08Errormismas rutasestados
UI-09Loadingmismas rutasestados
UI-10Tokens— (theme)Tailwind config / styles
UI-11Mobile bento/ @390TallerPage
UI-12Mobile encargo/encargo @390EncargoPage

4. Flujo prototipo clickable (orden demo)

UI-01 Home bento
  ├─→ UI-02 Configurador (Frenos)
  │     └─→ UI-03 Dejar bici → UI-04 Success
  ├─→ UI-11 (mismo /, viewport 390)
  ├─→ UI-12 (mismo /encargo, viewport 390)
  └─→ S-TOP Mesa → UI-05 Login → UI-06 Mesa

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

5. Datos de prototipo = seed

CodeModeloColorJobEstadoCover asset
PIN-2701Orbea urbanaverdeFrenosEN_TALLERbicis/orbea.jpg
PIN-2702BH paseocremaRevisiónLISTAbicis/bh.jpg
PIN-2703Classic foldnegraRuedaEN_TALLERbicis/fold.jpg
PIN-2704Trek niñoazulCadenaESPERAbicis/trek.jpg

Hotspots Paper deben usar estos códigos en labels si muestran URL. [DECISIÓN]
POST demo → PIN-2705 (Pablo Mora, frenos, verde).

6. Breakpoints de artboard

ArtboardAncho ref
Desktop bento / encargo / mesa~1280–1440
Mobile bento (UI-11)390
Mobile encargo (UI-12)390
Tokens (UI-10)según Paper

7. Terna visible en prototipo

CódigoEvidencia en UI
R-HYOficio clásico (S-TOP, ganchos) + configurador
S-TOPTaller · Encargo · Mesa en UI-01 / 11 / 06
H-BENTOUI-01 Deriva: tile + 3 datos + 4 bicis
F-CMPUI-02 antes de UI-03

8. Gaps conscientes

GapNotas
GPS / e-commerceL3 · no son huecos del prototipo L2
PATCH de estadoFuera · mesa de lectura
Analytics en prototipoModelo 12

Ningún gap es producto in-scope aplazado. [DECISIÓN]

9. Criterios de aceptación del mapa

  1. Cada UI-01…12 tiene fila en esta tabla.
  2. Cada ruta Must tiene artboard.
  3. No hay artboard de /buscar, /sesion, tienda, GPS o cita.
  4. Mobile 390 cubierto (UI-11, UI-12).
  5. UX-00…11 cubiertos.

18-completeness-audit.md

18 — Auditoría de cierre — PIÑÓN

1. Alcance L2 · una iteración

El vertical slice cierra en esta iteración. No hay segunda pasada de producto in-scope. Empty, error, loading, mobile, auth, seed, copy y contrato de código forman parte del cierre, no de un roadmap.

PiezaEstado
Docs 01–20 + README + executiveOK (este set)
00-day-briefIntactos (fuente de verdad)
00-paper-referenceOK · UX-count 12 · UI-count 12
Paper 12 UX + 12 UIInventario en 00 · file 01M110K5JHDQ899C360KC4D0WD
App path /Users/cristian/orca/pinon-appOK · GH Criscode2022/pinon-app
API :3027 · health pinon-apiContrato
Código bicis + requests + JWT MECANICOContrato doc 20
Cierre sin deuda del L2OK · roadmap solo L3 GPS / e-commerce

2. Terna y diversidad

CheckEvidencia
R-HY · S-TOP · H-BENTO · F-CMPBrief + 01 + 07
0 códigos = BOBINABOBINA era R-IN · S-DOCK · H-FEED · F-STORY
≥2 vs LOMO / ONDATop/Bento/Cmp vs cmd/data/lead y rail/gallery/search
S-TOP, H-BENTO, F-CMP no en últimos 5Brief
Ground G-GRAPHITE #2C303300 + 07 + Tailwind
No leftover BOBINA0 sesiones / PROGRAMADOR / dock en el contrato
Mood industrial ≠ neón fixie07
H-BENTO ≠ MATIZS-TOP + F-CMP; no editor de gramos

3. Copy irrenunciable

Presente en taller, encargo, success, pie de mesa. Ver doc 09.

  • Dejar la bici ≠ comprar el taller
  • Encargo ≠ cita de fitness
  • Recoger ≠ alquilar
  • PIÑÓN no es Decathlon

4. Anti-patrones vigilados

APMitigación
AP-12 hero 2-colH-BENTO Deriva tile + 3 datos + 4 bicis
AP-21 card huecaModelo/color/job/estado visibles
Leftover como estadoContrato PIÑÓN; no se anota BOBINA como producto vivo
Entrevistas inventadas02 etiquetado
sesiones/PROGRAMADOR/bobina-api0 en dominio; 05 + 20
ejemplares/BIBLIO0 en dominio
H-FEED / S-DOCKBento + S-TOP
H-DATA / S-CMDNo mesa de datos ni comando
KanbanMesa de ganchos
GPS / e-commerce en L2S4 · solo L3
Estadísticas inventadasEtiquetas [HIPÓTESIS]/[SUPUESTO]
Roadmap con deuda L2Doc 15 solo GPS / e-commerce

5. Seed

4 bicis · 2 EN_TALLER · 1 LISTA · 1 ESPERA · Nuria MECÁNICO · Pablo sin cuenta · Amparo fuera de login.

codemodeljobstatus
PIN-2701Orbea urbana verdeFrenosEN_TALLER
PIN-2702BH paseo cremaRevisiónLISTA
PIN-2703Classic fold negraRuedaEN_TALLER
PIN-2704Trek niño azulCadenaESPERA

Métricas: en taller 2 · listas 1 · esperan 1.

6. Assets

ArchivoPresente
assets/hero.jpg[COMPROBADO] case
assets/bicis/orbea.jpg[COMPROBADO]
assets/bicis/bh.jpg[COMPROBADO]
assets/bicis/fold.jpg[COMPROBADO]
assets/bicis/trek.jpg[COMPROBADO]

7. Huecos conscientes (fuera · L3)

GPS, e-commerce. Nada más se etiqueta como «faltó del L2».

Login Amparo, email transaccional, instrumentación analytics, PATCH de estado, ficha /mesa/:code no son deuda: son decisiones de corte (S2, S4, D14).

8. Checklist archivos suite

ArchivoEstado
README.mdOK
presentation/executive-summary.mdOK
docs/00-day-brief.mdPreexistente
docs/00-paper-reference.mdOK
docs/01 … docs/20OK

9. Veredicto

Slice L2 cerrado en una iteración. El contrato de pinon-app (docs 14 y 20) no se lista como próximo paso de producto: es el mismo alcance, ya definido. Paper file 01M110K5JHDQ899C360KC4D0WD. Si el repo diverge (leftover BOBINA), gana docs 05 + 20 tras alinear ambos.

Cierre: Must cubierto. Roadmap = L3 GPS y e-commerce únicamente.

10. SCORE ALS-2 (cierre)

EjeScoreNota
Diversidad5Taller de barrio nuevo; L2 no L1; no cineclub/feed/dock
Docs4Suite 00–20 + brief + presentation
Paper craft UI512 UI tokens/taller Deriva/configurador/dejar/success/login/mesa/empty/error+loading + 2 mobile
Paper UX process512 UX · gate UX=12 UI=12
Media5Hero nave + 4 bicis
Canvas org5Bandas § UX / IA / UI / Estados origen 0,0
Código E2E5GET bicis + POST encargos 201 PIN-2705 + JWT MECANICO; ng build
Paridad app4S-TOP + H-BENTO Deriva + tokens G-GRAPHITE
Unicidad estructura5R-HY · S-TOP · H-BENTO · F-CMP
Cierre admin5Registry+Excel+GitHub+Paper gate+portfolio UI-01
Media~4.8

Gate: node scripts/check-paper-reference.mjs 2026-08-27-pinonOK.

19-backlog-completo.md

19 — Backlog completo — PIÑÓN

1. Leyenda

EstadoSignificado
DoneDefinido y aceptado en la suite ALS L2 (esta iteración)
Won’t L2Fuera; L3 GPS / e-commerce u otro case

No hay columna «Must (después)». El slice no deja producto in-scope a medias. [DECISIÓN]

2. Épica A — Taller H-BENTO Deriva

IDÍtemEstado
A1Deriva tile nave a sangre + 3 métricas + 4 bicisDone
A2Tile: modelo, color, job, statusDone
A3CTA Encargo → /encargoDone
A4Empty / loading / errorDone
A5Mobile 390 + assets coversDone
A6Búsqueda comando /buscarWon’t L2 (≠ LOMO)
A7Feed de nochesWon’t L2 (≠ BOBINA)

3. Épica B — Configurador F-CMP

IDÍtemEstado
B1/encargo paso 1 · 4 jobsDone
B2Selección exclusiva rueda / frenos / cadena / revisiónDone
B3Continuar disabled sin jobDone
B4Copy irrenunciable en encargoDone
B5«Arréglame lo que sea» / multi-SKUWon’t L2 (H2)

4. Épica C — Dejar la bici

IDÍtemEstado
C1/encargo paso 2 · name + phone + colorDone
C2POST público 201 / 400Done
C3Crea bici ESPERA + requestDone
C4/ok/:code + 4 oposicionesDone
C5Pago / lineal / tallaWon’t L2 (≠ Decathlon · L3 e-commerce)
C6Signup vecinoWon’t L2 (S2)
C7GPS al dejarWon’t L2 (L3)

5. Épica D — Mesa MECÁNICO

IDÍtemEstado
D1Login JWT NuriaDone
D2/mesa ganchos ESPERA / EN_TALLER / LISTADone
D3GET mesa 401 sin tokenDone
D4LogoutDone
D5Requests con name + phoneDone
D6Kanban columnasWon’t L2 (≠ PREGÓN)
D7PATCH estado / ficha pedidoWon’t L2 (mesa de lectura)

6. Épica E — Chrome S-TOP

IDÍtemEstado
E1Top Taller · Encargo · MesaDone
E2aria-current + targets 44Done
E3Mesa guest → loginDone
E4Dock BOBINA / comando LOMO / bottom MATIZWon’t L2

7. Épica F — Design system & a11y

IDÍtemEstado
F1Tokens grafito/cream/card/mark/mute/chromeDone
F2Spectral + SoraDone
F3Contraste cream/grafito AADone
F4Reduced motionDone
F5Modo letra grande AmparoWon’t L2 (corte a11y, no deuda)

8. Épica G — Plataforma

IDÍtemEstado
G1Nest :3027 · health pinon-apiDone
G2Neon dedicado schema+seedDone
G3Angular rutas + guardDone
G4pnpm apps independientesDone
G5GPS / MapboxWon’t L2 · L3
G6E-commerce / StripeWon’t L2 · L3

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

IDÍtemEstado
H1docs 00–20 + README + executiveDone
H2Paper UX 12 + UI 12 inventarioDone
H3File 01M110K5JHDQ899C360KC4D0WDDone (ref)

10. Orden de build (mismo alcance, no roadmap)

  1. Schema + seed + health
  2. GET bicis + TallerPage Deriva
  3. EncargoPage paso 1 + paso 2
  4. POST encargos + OkPage copy
  5. Auth + MesaPage
  6. S-TOP + 390 + empty/error/loading
  7. Pulido tokens / a11y / smoke S01–S12

Ese orden no es «próximos pasos de producto»: es la receta del mismo L2 ya cerrado. [DECISIÓN]

11. Contadores

TipoCount (aprox)
Done L2~40
Won’t L2 / L3GPS, e-commerce + analogías vetadas
Docs DoneSuite completa

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

20-implementation.md

20 — Implementación — PIÑÓN

1. Resumen ejecutivo técnico

CampoValor
App path/Users/cristian/orca/pinon-app
GHCriscode2022/pinon-app
APINestJS · puerto 3027 · prefijo /api
WebAngular standalone · puerto 4200
Packageapps independientes (pnpm --filter)
DBNeon PostgreSQL · project dedicado PIÑÓN (DATABASE_URL)
Tablasusers, bicis, requests, sessions
AuthJWT Bearer · role MECANICO (/mesa); bento y POST encargos públicos
DominioUser, Bike, Request
Fecha2026-08-27
Healthpinon-api (leftover bobina-api → sustituir)

Este documento es la especificación de build del L2 ya cerrado. No es un roadmap: si el repo diverge, gana el contrato de docs 05 + este archivo tras actualizar ambos.

Contrato: bicis + requests + JWT MECANICO. Puerto 3027. Health pinon-api.

[COMPROBADO] Path, puerto y Paper salen del encargo.

El repo no debe contener leftover BOBINA (sesiones, PROGRAMADOR, bobina-api, puerto 3026) ni leftover LOMO (ejemplares, BIBLIO). Eso no es PIÑÓN.

2. Cómo arrancar

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

# apps/api/.env
#   DATABASE_URL=<neon PIÑÓN>
#   JWT_SECRET=<secret>
#   PORT=3027

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

Credenciales

RolEmailPassword
MECANICOnuria@pinon.tallerpassword123

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

Vecino / vecina mayor: sin cuenta. Pablo deja en /encargo. Amparo no entra por login.

3. Schema

Al boot o vía migrate:

  1. CREATE TABLE de users, sessions, bicis, requests (doc 05).
  2. Índices: bicis(code), bicis(status), bicis(sort_order), users(email), requests(bici_id), requests(created_at DESC).
  3. Seed idempotente:
    • upsert MECANICO nuria@pinon.taller (hash bcrypt canónico)
    • upsert bicis por code (PIN-2701PIN-2704) restaurando status, job, color, cover
    • upsert 4 requests seed (Elena, Luis, Marta, Iván)
  4. Dominio: solo bicis + requests + users. [DECISIÓN]

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

POST de encargo genera código nuevo (PIN-2705+). El success usa ese código.

Tablas (recordatorio)

TablaContenido
usersMECÁNICO Nuria Vega
bicis4 ganchos (+ las del POST)
requestsEncargos (seed + POST)
sessionssid + expires_at

DROP leftover sesiones, pedidos, ejemplares, programas si existen en el mismo Neon. [DECISIÓN] El project es de PIÑÓN.

Seed SQL (modelo)

codemodelcolorjobstatuscover
PIN-2701Orbea urbanaverdeFRENOSEN_TALLER/assets/bicis/orbea.jpg
PIN-2702BH paseocremaREVISIONLISTA/assets/bicis/bh.jpg
PIN-2703Classic foldnegraRUEDAEN_TALLER/assets/bicis/fold.jpg
PIN-2704Trek niñoazulCADENAESPERA/assets/bicis/trek.jpg

[SUPUESTO de taller] Modelos demo.

4. Módulos API a implementar

Auth

  • POST /api/auth/login
  • Valida email/password; compara bcrypt; emite JWT con sub, email, role.
  • Guard JWT + role === MECANICO protege /mesa.
  • Públicos: health, bicis, bicis/:code, POST encargos, login.

Oficio

MétodoRutaAuthNotas
GET/api/healthNo{ ok: true, service: "pinon-api" }
GET/api/bicisNometrics + sort_order asc sin name/phone
GET/api/bicis/:codeNoitem
POST/api/encargosNoINSERT bici ESPERA + request; 400 si job/name/phone/color inválidos
GET/api/mesaJWTganchos agrupados + requests con PII de mostrador

Health (referencia de implementación)

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

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

POST encargos — algoritmo

1. Validar body.job ∈ {RUEDA,FRENOS,CADENA,REVISION} else 400
2. Validar body.name (trim, length >= 2) else 400
3. Validar body.phone (dígitos >= 9) else 400
4. Validar body.color (trim, length >= 3) else 400
5. model = body.model?.trim() || 'bici'
6. code = siguiente PIN-XXXX (max existente + 1, piso PIN-2705)
7. INSERT bicis (code, model, color, job, status=ESPERA)
8. INSERT requests (bici_id, code, name, phone)
9. 201 { code, color, job, status: ESPERA, dejada: true }

Transacción única. [DECISIÓN]

GET bicis — shape

{
  "metrics": { "enTaller": 2, "listas": 1, "esperan": 1 },
  "bicis": [ { "code", "model", "color", "job", "status", "cover", "sortOrder" } ]
}

Métricas: count status EN_TALLER / LISTA / ESPERA. No ENTREGADA. [DECISIÓN]

GET mesa — shape

{
  "metrics": { "enTaller": n, "listas": n, "esperan": n },
  "ganchos": {
    "ESPERA": [ /* bicis */ ],
    "EN_TALLER": [ /* bicis */ ],
    "LISTA": [ /* bicis */ ]
  },
  "requests": [ { "id", "code", "name", "phone", "job", "status", "createdAt" } ]
}

Orden requests: created_at DESC. [DECISIÓN]

5. Frontend Angular

Rutas

PathComponentGuard
''TallerPage
encargoEncargoPage
ok/:codeOkPage
loginLoginPage
mesaMesaPageauthGuard
**redirect ''

Servicios

ServiceResponsabilidad
BicisApiGET list/detail
EncargosApiPOST encargos
AuthApilogin, token store, logout
MesaApiGET mesa con Bearer
TopNavStateslot activo

UI Must

  1. TallerPage — tile + 3 datos + 4 bicis (Deriva), no feed ni tabla.
  2. EncargoPage — F-CMP paso 1 y 2.
  3. OkPage — código + 4 oposiciones.
  4. LoginPage / MesaPage.
  5. TopNavComponent — S-TOP.
  6. Estados empty/error/loading.

Tailwind tokens

ground: #2C3033
cream: #F3F1EC
card: #1A1C1B
mark: #E24A17
mute: #8B8E8A
chrome: #C5C8C4
font-display: Spectral
font-sans: Sora

6. Assets en app

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

  • orbea.jpg
  • bh.jpg
  • fold.jpg
  • trek.jpg

hero.jpg → tile Deriva (/assets/hero.jpg).

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

7. Checklist anti-leftover

Prohibido en runtimeSustituto
bobina-apipinon-api
puerto 30263027
sesiones / pedidosbicis / requests
PROGRAMADORMECANICO
BOB-XXXXPIN-XXXX
/sesion /pedir/ /encargo
ABIERTA/COMPLETAESPERA/EN_TALLER/LISTA
Cormorant / Manrope velvetSpectral / Sora industrial
G-VELVET #1A1210G-GRAPHITE #2C3033
Dock Cartelera · Pedir · MesaS-TOP Taller · Encargo · Mesa

8. DoD técnico (merge)

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

9. Fuera de esta especificación

  • GPS (L3).
  • E-commerce (L3).
  • Instrumentación analytics (doc 12 modelo).
  • PATCH de estado (mesa de lectura).

Ninguno de esos ítems es un «siguiente paso» del L2. [DECISIÓN]

10. Cierre

Implementación = contrato ejecutable del case 2026-08-27-pinon, cerrado en una iteración. [COMPROBADO] alcance L2.