On this page 00 — Day brief · 2026-08-17 · MARGEN 0%

00-day-brief.md

00 — Day brief · 2026-08-17 · MARGEN

Decisiones ALS-2 BRIEF

CampoValor
Fecha2026-08-17
NombreMARGEN
ComplejidadNivel 2 (no L1 consecutivo tras CESTA)
SectorEditorial local / familias (semanario vecinal)
TipoLookbook de números + lectura de crónicas + agenda familiar + mesa EDITOR JWT
PlataformaWeb responsive (galería editorial desktop · lector mobile · mesa redacción)
RegistroR-CL — kiosco / revista de barrio, rigor tipográfico
ShellS-TOP — cabecera de periódico (masthead + secciones)
HomeH-GALLERY — portadas y piezas como lookbook, no hero 2-col
FlujoF-STORY — hojear número → leer crónica (no cola de leads)
Por qué no CESTANo S-RAIL / H-TABLE / F-LEAD; no ONG; no tabla de necesidades
Por qué no RONDANo S-DOCK / H-FEED / F-BOOK; no gaming

Terna unicidad

R-CL · S-TOP · H-GALLERY · F-STORY

0 códigos iguales a N−1 (CESTA). ≥2 distintos vs N−2 (RONDA) y N−3 (DERIVA). Ventana 4 días ya tenía R-IN (DERIVA) y R-HY (RONDA); hoy R-CL editorial.

Ground (CRON §5.6)

  • Familia: G-GALLERY
  • Hex: #FFFFFF
  • Por qué: kiosco / papel prensa. No es G-MOSS (CESTA), G-CHROME (RONDA), G-WATER (DERIVA), G-MUNICIPAL (PIZARRA) ni G-ICE (PRIMA).

Mood visual (Paper)

  • Candidatos: bookish plaster×ink (primer instinto), chapel, candlelit, gallery / newsstand
  • Elegido: gallery / newsstand — no el primer instinto bookish
  • Paleta: #FFFFFF papel · #16141A tinta · #C41E3A cadmio · #5C5866 grafito · #F4F1EA pliego (solo cards) · #E8E4DC filete
  • Tipo: Cormorant Garamond display · Public Sans UI (evita Newsreader / Outfit / Spectral / Manrope / Zilla / Mulish / Lora / Karla)

Alcance L2 must

  1. Home lookbook: número en curso + ≥3 portadas/piezas con lead (visibles en recorte 16:10)
  2. Ficha de crónica (kicker, título, cuerpo, crédito)
  3. Agenda familiar de la semana (3 eventos reales)
  4. Login + mesa EDITOR JWT (DRAFT → PUBLISHED)
  5. Alta de pieza + success
  6. Empty / loading / error / mobile lector
  7. ≥12 UX + ≥10 UI

Microcopy duro

  • Publicar ≠ imprimir. El número digital no es el tiraje de kiosco.
  • Borrador ≠ publicado. La familia no ve DRAFT.
  • Agenda ≠ inscripción. El evento se lee; no se reserva plaza (≠ PIZARRA).

Supuestos

  • S1: Un semanario de barrio cierra 1 número / semana y 4–8 piezas (demo: 1 número + 4 piezas + 3 eventos).
  • S2: La lectora llega por “qué hay esta semana”, no a suscribirse a un paywall.
  • S3: La redacción es 1–2 personas; la mesa es lista de piezas, no un CMS enterprise.
  • S4: No hay comentarios ni likes. El producto es lectura + publicación.

Hipótesis

IDSeñal
H1El lookbook de portadas reduce “¿dónde está el PDF del cole?” vs hilos de WhatsApp
H2Separar agenda de inscripción evita la expectativa de reserva
H3JWT solo en redacción basta; el lector no necesita cuenta

00-paper-reference.md

Paper reference · MARGEN

URLhttps://app.paper.design/file/01M078GFW7QQF5RRA2XGKQ8BD9
File ID01M078GFW7QQF5RRA2XGKQ8BD9

UX-count: 12 UI-count: 12

UX-00 Cover · UX-01 Stakeholders · UX-02 Personas · UX-03 JTBD · UX-04 Stories · UX-05 Journey · UX-06 Blueprint · UX-07 Site map · UX-08 Flujos · UX-09 Datos+permisos · UX-10 Métricas · UX-11 Research UI-00 Tokens · UI-01 Lookbook · UI-02 Crónica · UI-03 Agenda · UI-04 Login · UI-05 Mesa · UI-06 Alta pieza · UI-07 Success · UI-08 Empty · UI-09 Error · UI-10 Loading · UI-11 Mobile lector

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

IDNombreContenido
UX-00CoverPortada MARGEN · eslogan «La semana del barrio, en un número.» · terna R-CL · S-TOP · H-GALLERY · F-STORY · L2 editorial local familias · mood gallery/newsstand · fecha 2026-08-17
UX-01StakeholdersLECTORA anónima (Elena), EDITOR (Nuria), AMPA (Raúl), cole, biblioteca, vecinos de Usera / Carabanchel / Villaverde — no paywall, no inscripción
UX-02PersonasElena Vargas (38, lectora, Usera, dos hijos) · Nuria Ceballos (44, editora, mesa de 1–2) · Raúl Méndez (42, AMPA Carabanchel)
UX-03JTBDJob «qué hay esta semana en el barrio» + job «cerrar el número y publicar la crónica» + job «que el cole se lea, no se reserve»
UX-04StoriesMust: lookbook del número + ≥3 portadas, ficha de crónica, agenda 3 eventos, login EDITOR, mesa DRAFT→PUBLISHED, alta + success, empty/error/loading, mobile lector
UX-05JourneyHojear lookbook → leer crónica → consultar agenda → (EDITOR) login → mesa → nueva pieza → publicar
UX-06BlueprintFrontstage masthead/galería/ficha/agenda · backstage cierre de número y WhatsApp del AMPA · sistemas Nest/Neon/JWT
UX-07Site map / IAPúblico gallery-first + auth EDITOR; S-TOP Número · Agenda · Mesa
UX-08FlujosF-STORY: lookbook → crónica → agenda; F-DESK: login → lista → alta → PATCH PUBLISHED
UX-09Datos + permisosUser EDITOR · Issue · Piece · Event; JWT en GET mesa / POST / PATCH; público no ve DRAFT
UX-10MétricasNorth star % sesiones que abren ≥1 pieza y ven agenda; publicar no cuenta como tiraje
UX-11Research notesComprobado / supuesto / hipótesis / decisión — sin entrevistas de campo inventadas

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

IDNombreFlujo
UI-00TokensDS gallery/newsstand: papel, tinta, cadmio, grafito, pliego, filete; Cormorant Garamond + Public Sans
UI-01LookbookH-GALLERY: número en curso + ≥3 portadas/piezas con lead, recorte 16:10 visible
UI-02CrónicaFicha: kicker, título, cuerpo, crédito, cover
UI-03AgendaSemana familiar, 3 eventos; se leen, no se inscriben
UI-04LoginAcceso JWT EDITOR a la mesa
UI-05MesaLista de piezas DRAFT / PUBLISHED + CTA nueva
UI-06Alta piezaForm de crónica (título, kicker, cuerpo, sección, cover)
UI-07SuccessAcuse de publicación + aviso «no es el tiraje de kiosco»
UI-08EmptyNúmero sin piezas publicadas
UI-09ErrorFallo de red, reintentar
UI-10LoadingCerrando el número
UI-11Mobile lectorHome galería 390px + 3 leads

Regla: wizard de N pasos → N boards UI solo para esos pasos, además de success/empty/error/loading/staff. MARGEN no es wizard: el núcleo es lookbook → crónica → agenda y mesa → alta → publicar.

Paper se construye en paralelo a esta suite. Los nombres de la tabla son el inventario planificado; el file ID ya existe.


1. Mapa de canvas (bandas)

§BandaPropósitoArtboards clave
1UX PROCESSModelo de servicio de semanario vecinalUX-00…UX-11
2DESIGN SYSTEMTokens gallery + masthead + card pliegoUI-00
3PUBLIC GALLERYCara lectora lookbook / lectura / agendaUI-01, UI-02, UI-03, UI-08, UI-10
4EDITORFlujos autenticadosUI-04, UI-05, UI-06, UI-07
5STATESResilienciaUI-08, UI-09

Layout canvas (referencia de diseño): origen (0,0) · gaps ~100–120px · UX en 3×4 · UI pública en fila lookbook → crónica → agenda · mesa en fila login → lista → alta → success · mobile debajo del lookbook. [DECISIÓN] Bandas jerárquicas D-P0-04 / D-P1-04.


2. Mapeo Paper → Angular

ArtboardRuta appComponente
UI-00 Tokenstokens Tailwind + fuentes
UI-01 Lookbook/HomePage (galería del número)
UI-02 Crónica/piezas/:slugPiecePage
UI-03 Agenda/agendaAgendaPage
UI-04 Login/loginLoginPage
UI-05 Mesa/mesaDeskPage
UI-06 Alta pieza/mesa/nuevaNewPiecePage
UI-07 Success/mesa/ok/:slugOkPage
UI-08 Empty / Error/ 0 piezas · /agenda 0 eventos · /mesa 0 filasempty / banner error + retry
UI-09 Loadinglookbook / mesa / agendaskeletons de cards / filas
UI-10 Mobile lector/ y /piezas/:slug viewport 390mismos pages + tipografía de lectura

[COMPROBADO] Rutas del encargo. No hay /inscribir, /comentarios, /suscribir, search-first ni hero 2-col.


3. Tokens de diseño en Paper

TokenValorUso
Papel / ground#FFFFFFFondo de página, kiosco
Tinta#16141ATexto fuerte, wordmark, cuerpo
Cadmio#C41E3AAcento, filete de masthead, PUBLISHED, CTA
Grafito#5C5866Meta, kicker, crédito, nav idle
Pliego#F4F1EACards de pieza / evento (no el ground)
Filete#E8E4DCBordes, rules, skeletons
DisplayCormorant Garamond 56/40/28Titulares, wordmark, título de crónica
UIPublic Sans 16/14Body UI, labels, form, nav, agenda

[COMPROBADO] Hex y tipo salen de docs/00-day-brief.md. Mood elegido: gallery / newsstand, no el primer instinto bookish plaster×ink.


4. Checklist de densidad (anti thin-frames)

CriterioUXDSPublic galleryEDITORStates
Jerarquía tipográfica visible
Microcopy real (no lorem)
Tokens gallery aplicados
Datos de seed creíblesPersonas4 piezas + 3 eventos + fotos1 DRAFT en mesaEmpty realista
Media / iconografíaCoverFotos de barrioBadges DRAFT/PUBLISHEDSkeletons
Masthead S-TOP presenteSpecUI-01, UI-02, UI-03, UI-10UI-05
Galería (no tabla, no feed)SpecUI-01, UI-10
Recorte 16:10 visible en portadasSpecUI-01

5. Media

  • assets/hero.jpg — atmósfera de kiosco / semanario abierto en mesa de cocina, café y cuaderno de niños
  • assets/merienda.jpg — Patio de manzana, familias en banco de piedra, merienda
  • assets/colegio.jpg — Puerta de CEIP, mochilas en la valla, espera de madres y padres
  • assets/piscina.jpg — Vaso municipal de verano, bloques de ladrillo al fondo
  • assets/biblioteca.jpg — Sala de lectura municipal, patio y cartel «Biblioteca Municipal»

[COMPROBADO] Los cinco archivos existen en el case 2026-08-17-margen/assets/.


6. Enlaces

01-project-definition.md

01 — Definición de proyecto — MARGEN

1. Identidad

CampoValor
NombreMARGEN
SignificadoEl margen de la página (filete, blanco, kicker) y el margen sur de Madrid: Usera, Carabanchel, Villaverde. Semanario de familias, no revista de centro.
Eslogan”La semana del barrio, en un número.”
Una fraseLookbook del número semanal + lectura de crónicas + agenda familiar + mesa EDITOR JWT.
SectorEditorial local / familias (semanario vecinal)
TipoWeb L2 — galería + crónica + agenda + mesa EDITOR — Nivel 2, craft alto
PlataformaWeb responsive (galería editorial desktop · lector mobile · mesa redacción)
Mercado demoEspaña · Madrid · Usera / Carabanchel / Villaverde (un solo semanario, no red multi-distrito)
Idiomaes-ES
Fecha caso2026-08-17
TernaR-CL · S-TOP · H-GALLERY · F-STORY

[COMPROBADO] Nombre, terna, nivel, sector, ground y paleta salen de docs/00-day-brief.md.

2. Problema

Principal (hipótesis de diseño)

[HIPÓTESIS] La familia del sur de Madrid no abre un paywall ni un PDF institucional: pregunta “qué hay esta semana” en el grupo del cole, el del patio y el de la AMPA. El recado se pierde, el cartel se desactualiza y el “PDF del cole” circula en tres versiones. [SUPUESTO] La redacción de un semanario de barrio es 1–2 personas; no opera un CMS enterprise ni una mesa de inscritos.

Secundarios

ProblemaQuién lo sufreEfecto
“¿Dónde está el PDF del cole?” enterrado en hilosLECTORA (Elena)Llega tarde a la merienda, al vaso, a la hora del cuento
Número digital confundido con tiraje de kioscoAmbos“¿Cuándo lo imprimís?”; expectativa de papel
Borrador visible en homeEDITOR (Nuria) + lectoraCrónica a medias se lee como publicada
Agenda leída como inscripciónAMPA (Raúl) + lectora“Ya estoy apuntada” cuando solo había un horario
Mesa de redacción = Excel + DriveEDITORCierra el número en chats, no en una lista

Supuestos (no investigación primaria propia)

  • S1: Un semanario de barrio cierra 1 número / semana y 4–8 piezas (demo: 1 número + 4 piezas + 3 eventos). [SUPUESTO]
  • S2: La lectora llega por “qué hay esta semana”, no a suscribirse a un paywall. [SUPUESTO]
  • S3: La redacción es 1–2 personas; la mesa es lista de piezas, no un CMS enterprise. [SUPUESTO]
  • S4: No hay comentarios ni likes. El producto es lectura + publicación. [SUPUESTO]

Hipótesis de producto

IDHipótesisSeñal de validación (futura)
H1El lookbook de portadas reduce “¿dónde está el PDF del cole?” vs hilos de WhatsApp% sesiones con tap en card de pieza
H2Separar agenda de inscripción evita la expectativa de reserva↓ “pensé que ya estaba apuntada”
H3JWT solo en redacción basta; el lector no necesita cuenta0 cuentas de lectora; lectura completa sin login

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

3. Propuesta de valor

ParaValor
LECTORA (Elena Vargas)Ve el número de la semana en un lookbook; lee la crónica; consulta la agenda sin crear cuenta.
EDITOR (Nuria Ceballos)Lista las piezas, escribe una nueva, publica DRAFT → PUBLISHED sin un CMS de 40 tipos.
AMPA (Raúl Méndez)La crónica del cole y la cita de la semana se leen en un sitio; no convierte MARGEN en matrícula.
Barrio / semanarioCanal mínimo: número visible + lectura + cierre editorial, sin paywall ni comentarios.

No es MARGEN

ExcluidoPor qué
Paywall / suscripción / cuenta lectoraS2 + H3: llega a leer, no a darse de alta
Inscripción / reserva de plazaAgenda ≠ inscripción (≠ PIZARRA)
Tabla de necesidades / compromiso de cajaEso fue CESTA (H-TABLE / F-LEAD)
Feed / cronología de “historias”Terna H-GALLERY, no H-FEED (eso fue RONDA)
Mapa de paseosTerna no es H-MAP (eso fue DERIVA)
Search-first / catálogo facetadoTerna no es H-SEARCH (eso fue PIZARRA)
Comentarios, likes, rankingS4
Tiraje / impresión / kiosco físicoPublicar ≠ imprimir
Hero 2-col + 3 cards de “cómo leer”Anti-patrón AP-12; contradice H-GALLERY

4. Objetivos

Negocio / caso de estudio

  • Demostrar vertical slice L2 editorial gallery-first con Issue + Piece + Event + JWT EDITOR.
  • Portfolio coherente: Paper (12 UX + 11 UI) + docs + app runnable.
  • Terna R-CL · S-TOP · H-GALLERY · F-STORY frente a CESTA (tabla/rail), RONDA (feed/dock) y DERIVA (mapa).

Usuario

RolObjetivo medible en demo
LECTORAVer el número y abrir una crónica en < 30 s; llegar a la agenda en 1 tap más
EDITORPublicar una pieza DRAFT → PUBLISHED en < 2 min desde la mesa
AMPALeer un evento de la semana sin encontrar un CTA de reserva

No objetivos v1 (explícitos)

  • Paywall, newsletter transaccional, cuenta de lectora
  • Comentarios, likes, bookmarks
  • Inscripción / cupo / WAITLIST
  • Multi-número archivo con búsqueda
  • CMS de tipos, taxonomías profundas, workflow de 5 estados
  • Impresión / PDF de kiosco / punto de venta
  • Multi-editor con roles (redactor / jefe / fotógrafo)
  • App nativa ni notificaciones push

5. Roles y permisos (resumen)

AcciónPúblico (LECTORA / AMPA)EDITOR
Ver lookbook del número PUBLISHED
Leer pieza PUBLISHED
Ver pieza DRAFTNo (404) (mesa)
Ver agenda de la semana
Inscribirse a un eventoNo (no existe)No
Login JWTNo (no cuenta lectora)
Listar piezas de mesaNo (401)
Crear piezaNo
Publicar / despublicarNo
Crear IssueNo (seed v1)No en v1

[DECISIÓN] Un solo rol autenticado: EDITOR. La lectora es anónima. AMPA no es un rol de sistema: es persona / stakeholder que usa la cara pública.

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

TipoMétricaDefinición
North Star% de sesiones que abren ≥1 pieza y consultan /agenda en la misma semana del númeroCompletud de lectura del número, no pageviews
Activación lectora1.er tap en card de piezaH1
Activación editora1.er PATCH a PUBLISHEDCierre de número
ExpectativaReclamaciones “ya estoy apuntada” / “¿cuándo lo imprimís?”H2 + microcopy
IntegridadGET público no devuelve DRAFTBorrador ≠ publicado
SaludError rate API issues/pieces/events4xx/5xx

7. Alcance funcional v1 (L2)

MóduloIncluido
Home lookbookNúmero en curso + ≥3 portadas/piezas con lead (recorte 16:10 visible) + masthead
Ficha de crónicaKicker, título, cuerpo, crédito, cover
Agenda3 eventos reales de seed (título, startsAt, place, audience)
AuthPOST /api/auth/login → JWT EDITOR
MesaGET lista DRAFT + PUBLISHED, PATCH :id { status }
AltaForm + POST /api/pieces + success
Estados UIEmpty, loading skeleton, error de red
Mobile lectorMisma home y ficha a ~390px
Seed1 EDITOR, 1 Issue, 4 piezas PUBLISHED, 1 DRAFT, 3 eventos

8. Criterios de aceptación de producto

  1. Un visitante puede ver el lookbook del número sin autenticación y abrir una crónica.
  2. Un visitante puede leer la agenda sin cuenta y sin encontrar un CTA de reserva o inscripción.
  3. La UI dice explícitamente que publicar no es imprimir (success de mesa y, si cabe, pie de número).
  4. Sin token, GET /api/mesa/pieces y POST/PATCH de piezas responden 401.
  5. GET /api/issues/current devuelve el número PUBLISHED con ≥3 piezas publicadas.
  6. GET /api/pieces/:slug de un DRAFT responde 404 (no 200 + aviso).
  7. Un EDITOR puede iniciar sesión y ver la mesa con DRAFT y PUBLISHED.
  8. El EDITOR puede crear una pieza y publicarla (DRAFTPUBLISHED).
  9. La home es galería: no hay hero 2-col + 3 cards como superficie principal.
  10. Fotos reales en portada y piezas (assets del case).
  11. Recorte 16:10 de las portadas es visible (no recorte 1:1 que recorta el lead).
  12. Rutas públicas y de mesa solo las del doc 03.

9. Stack y artefactos

CapaDetalle
FrontendAngular + Tailwind · puerto 4200
BackendNestJS · puerto 3017
DBNeon PostgreSQL · project morning-truth-64427459
AuthJWT (EDITOR)
DiseñoPaper 01M078GFW7QQF5RRA2XGKQ8BD9
Repo app/Users/cristian/orca/margen-app/ · GitHub Criscode2022/margen-app

[COMPROBADO] Puerto, Neon, Paper file ID, repo y path de app constan en el encargo.

10. Riesgos y mitigaciones

RiesgoImpactoMitigación v1
Expectativa de reserva en agendaReclamaciones AMPA / “ya estoy apuntada”Copy “se lee, no se reserva”; sin botón Inscribirse
Expectativa de tiraje“¿Dónde lo compro?”Publicar ≠ imprimir en success y pie
DRAFT filtrado a homeCrónica a medias públicaGET público filtra status=PUBLISHED; slug DRAFT → 404
Home percibida como landing de revista genéricaPérdida de craftLookbook 16:10 + masthead; no hero 2-col
Confundir con PIZARRA (talleres + plaza)Expectativa de cupoEvent no tiene seats ni form
Confundir con CESTA (lista + compromiso)Expectativa de “traer algo”No hay form público de captura
Leftover walks / requests en repoApp enseña otro productoContrato de esta suite gana; I01 de build
PII de lectoraNo aplica v1Lectora no deja datos; EDITOR es la única cuenta
Número vacío un martesAbandonoEmpty “este número aún no tiene piezas publicadas”

11. Glosario

TérminoDefinición en MARGEN
Númeroissues: semana cerrada o en curso (weekLabel, cover, status)
Pieza / crónicapieces: texto con kicker, cuerpo, cover, sección
KickerAntetítulo de sección (Patio, Cole, Barrio, Lectura)
Agendaevents de la semana del número; no es inscripción
MesaSuperficie EDITOR: lista + alta + publicar
PublicarPasar pieza (o número) a PUBLISHED; no es imprimir
BorradorDRAFT; la familia no lo ve
LECTORAVisitante anónima que lee
EDITORUsuario autenticado que opera la mesa
PliegoSuperficie de card #F4F1EA, no el ground
MastheadShell S-TOP: wordmark + secciones + filete cadmio
LookbookHome H-GALLERY: portadas como galería, no feed ni tabla

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

IDDecisiónAlternativa descartada
D1Home = lookbook de portadas (H-GALLERY)Hero 2-col + 3 cards (AP-12) · tabla (CESTA) · feed (RONDA) · mapa (DERIVA) · search (PIZARRA)
D2Shell masthead de periódico (S-TOP)Rail de iconos · dock flotante · sidebar CMS · command search
D3Registro clásico de kiosco (R-CL)Bookish plaster×ink (primer instinto) · chapel · candlelit
D4Flujo F-STORY (hojear → leer)F-LEAD, wizard, kanban, booking, search
D5Mood gallery / newsstandBookish (vetado como primer instinto), botanical CESTA, chrome RONDA
D6Un rol autenticado EDITORMulti-rol lectora / AMPA / fotógrafo / admin
D7Estados solo DRAFT / PUBLISHEDSCHEDULED / REVIEW / KILLED (CMS enterprise)
D8Agenda de solo lecturaForm de plaza, cupo, WAITLIST (PIZARRA)
D9Lectora sin cuentaPaywall, newsletter obligatoria, comentarios
D10PATCH /api/pieces/:id { status }Subruta /publish como único contrato (puede existir alias, no Must)
D11Ground G-GALLERY #FFFFFFG-MOSS, G-CHROME, G-WATER, G-MUNICIPAL, G-ICE
D12Success de publicación en /mesa/ok/:slugToast único sin pantalla (L2 pide success board)

13. Relación con el día anterior

CaseTernaPor qué MARGEN no lo copia
CESTA (N−1)S-RAIL / H-TABLE / F-LEADNo ONG, no tabla de necesidades, no compromiso, no rail
RONDA (N−2)S-DOCK / H-FEED / F-BOOKNo gaming, no cronología, no dock, no sillas
DERIVA (N−3)S-SPLIT / H-MAP / F-MAPNo turismo, no plano, no split mapa
PIZARRAS-CMD / H-SEARCH / F-SEARCHAgenda se lee; no se pide plaza

[COMPROBADO] El brief fija terna R-CL · S-TOP · H-GALLERY · F-STORY. S / H / F son 0 coincidencias con CESTA (S-RAIL · H-TABLE · F-LEAD). Ventana 4 días ya tenía R-IN (DERIVA) y R-HY (RONDA); hoy R-CL editorial, distinto de CESTA en shell, home y flujo. Ground G-GALLERY #FFFFFF, no G-MOSS.

02-ux-research-strategy.md

02 — Estrategia de investigación UX — MARGEN

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 semanario vecinalModelado de stakeholders + personas§3–4
Definir job de “qué hay esta semana” y de cierre de númeroJTBD + stories Must§5
Mapear fricción WhatsApp / PDF → lecturaJourney + service blueprint§6–7
Traducir a requisitos L2 gallery-firstMatriz hallazgo → requisito → feature§8

2. Fuentes y límites

Fuentes admisibles (secundarias / operativas)

  • Conocimiento general de semanarios de barrio, grupos de WhatsApp de AMPA y cartelería de cole / biblioteca / piscina municipal.
  • Analogía operativa con lookbook editorial + mesa JWT de la serie daily.
  • Restricciones ALS-2: no tabla de leads, no feed, no mapa, no search-first, no inscripción, no paywall.

Límites éticos de verdad

ProhibidoPermitido
“El 71% de madres de Usera no encuentra el PDF del cole” sin fuente[SUPUESTO] la lectora llega con ‘qué hay esta semana’”
Citas de entrevistas ficticias como campo realQuotes de persona etiquetadas como constructo de diseño
Tirada medida “4.200 lecturas el domingo” como KPI realNorth star modelo “sesión que abre pieza + agenda”
Horario oficial de una biblioteca o CEIP concretoEventos de seed de producto, etiquetados como demo
“Nuria existe y nos dijo…”Nuria Ceballos es persona de diseño

3. Stakeholders

StakeholderInfluenciaInterésNecesidad principal
LECTORA / familia (Elena)Baja formalMuy altaVer el número de la semana y leer sin cuenta
EDITOR / redacción (Nuria)AltaMuy altaCerrar piezas y publicar sin CMS enterprise
AMPA (Raúl)Media–altaAltaQue la crónica del cole y la cita se vean; no gestionar plazas aquí
Niños (Hugo, Inés)IndirectaAltaQue el patio, el vaso y el cuento existan en el número
Cole / direcciónMedia adopciónMediaNo convertir MARGEN en secretaría virtual
Biblioteca / vaso municipalBaja v1MediaAparecer en agenda sin cupo online
Kiosco / imprentaBaja v1BajaFuera: publicar ≠ imprimir
WhatsApp del grupoCompetencia / canal paraleloNo clonar el chat; sí sustituir el PDF perdido

Mapa de poder (resumen)

  • Decisor de adopción: la editora (quien cierra el número) y, en difusión, el AMPA (quien pega el enlace).
  • Usuario frecuente de lectura: LECTORA (lookbook + ficha + agenda).
  • Usuario frecuente de publicación: EDITOR (mesa).
  • Riesgo de rechazo: si la home no enseña portadas en el primer viewport; si la agenda parece un formulario de plaza; si un DRAFT se filtra.

4. Personas

P1 — Elena Vargas · LECTORA

CampoDetalle
Edad / contexto38 años; Usera; dos hijos (Hugo 11, Inés 7); el móvil es el kiosco
DigitalMedia; lee en el sofá o en la cola del cole; WhatsApp todo el día; evita “suscríbete para seguir leyendo”
GoalsSaber qué hay esta semana, leer una crónica de un tirón, mirar la agenda del sábado
PainsTres PDFs del cole, el cartel de la biblioteca que nadie fotografía bien, meriendas que se entera el lunes
Quote de diseño“Dime qué hay esta semana. No me hagas una cuenta.”
Seed demoSin email de producto; llega por enlace del grupo

Escenario: Abre MARGEN, ve El patio no cierra en agosto, entra a La merienda que no cabe en el grupo, pasa a Agenda, anota Pradolongo el sábado. No se registra.

[DECISIÓN] Elena no tiene cuenta. Crear usuario de lectora sería fricción y contradice H3 / S2.

P2 — Nuria Ceballos · EDITOR

CampoDetalle
Edad / contexto44 años; redactora del semanario; cierra 4–8 piezas entre jueves y domingo
DigitalMedia–alta; desktop para escribir; móvil para revisar la home publicada
GoalsVer el estado de cada pieza, escribir una nueva, publicar sin “programar newsletter”
PainsDrive + WhatsApp + un Word por crónica; miedo a publicar un borrador; nadie entiende que digital ≠ kiosco
Quote de diseño“Si está en DRAFT, la familia no lo ve. Si lo publico, no lo estoy mandando a imprenta.”
Email demoredaccion@margen.barrio / password123

Escenario: Login → mesa → ve Lo que el AMPA no va a colgar en Stories en DRAFT → termina → Publicar → success con aviso de que no es el tiraje.

[COMPROBADO] Credencial demo sale del encargo. Nombre y edad son constructo de diseño. [DECISIÓN]

P3 — Raúl Méndez · AMPA

CampoDetalle
Edad / contexto42 años; Carabanchel; tesorero informal de un AMPA de CEIP; pega enlaces al grupo
DigitalMedia; WhatsApp y Drive; desconfía de “plataformas educativas” con matrícula
GoalsQue la charla de vuelta al cole se lea; que la crónica de la puerta se vea el domingo
PainsCada cita se convierte en “¿cómo me apunto?”; el PDF se pisa con otra versión
Quote de diseño“Que se lea. La lista de firmas la hago yo en el patio, no aquí.”

Escenario: Abre Agenda, ve Charla de vuelta al cole el lunes 18:00, copia el dato al grupo. No hay botón Inscribirse.

[DECISIÓN] Raúl no es rol de sistema. No hay login AMPA en L2. Evita convertir MARGEN en PIZARRA.

Anti-personas

QuiénPor qué no es target v1
Suscriptora de paywall / “socios del papel”S2: no hay cuenta ni cobro
Community manager que quiere comentarios y likesS4; rompe F-STORY
Coordinadora municipal de talleres que gestiona cupoEso es PIZARRA
Vecina de CESTA que pregunta “qué falta en la despensa”Otro job, otro día
Jefe de producto de CMS enterprise (40 tipos, workflow)S3: mesa de 1–2

5. JTBD y user stories

Job principal (LECTORA)

Cuando se acaba la semana y el grupo del cole echa humo,
quiero ver el número y leer qué pasa en el patio, el cole y el barrio,
para no perseguir el PDF ni enterarme el lunes de la merienda.

Job principal (EDITOR)

Cuando cierro el número del domingo,
quiero listar las piezas, escribir la que falta y publicarla,
para que la familia vea solo lo cerrado y yo no confunda borrador con kiosco.

Job principal (AMPA)

Cuando hay una cita de la semana (charla, merienda, cuento),
quiero que se lea en la agenda del número,
para difundirla sin que MARGEN se convierta en hoja de inscripción.

Jobs secundarios

JobRol
Distinguir número en curso de un DRAFTAmbos
Leer una crónica de un tirón en el móvilLECTORA
Ver crédito y kicker (quién escribe, de qué sección)LECTORA
Publicar sin mandar a imprentaEDITOR
Ocultar un borrador a la homeEDITOR
Compartir un evento por texto (día, sitio, público)AMPA

Stories Must (v1)

IDStoryAC
US1Como lectora, quiero ver el número y sus portadasGET /api/issues/current; ≥3 cards 16:10 con lead
US2Como lectora, quiero abrir la crónica con kicker, título, cuerpo y créditoGET :slug; foto real; autor
US3Como lectora, quiero ver la agenda de la semanaGET /api/events; 3 eventos; sin CTA de reserva
US4Como lectora, no quiero crear cuentaCero forms de registro en cara pública
US5Como EDITOR, quiero entrar con email/passwordJWT + redirect /mesa
US6Como EDITOR, quiero listar DRAFT y PUBLISHEDGET /api/mesa/pieces JWT
US7Como EDITOR, quiero crear una piezaPOST /api/pieces → DRAFT
US8Como EDITOR, quiero publicarlaPATCH { status: "PUBLISHED" } + success
US9Como cualquiera, quiero empty / error / loadingUI-08, UI-09
US10Como lectora en móvil, quiero leer a ~390pxUI-10; cuerpo ≥16px; targets ≥44px

MoSCoW (v1 L2)

PrioridadÍtems
MustLookbook, ficha, agenda 3 eventos, login, mesa, alta, success, empty/loading/error, mobile lector
ShouldBadge DRAFT/PUBLISHED en mesa; pie “publicar ≠ imprimir”; kicker visible en card
CouldCopiar enlace de pieza; despublicar a DRAFT; ordenar mesa por updatedAt
Won’tPaywall, comentarios, inscripción, archivo search, impresión, multi-editor

6. Journey (LECTORA → EDITOR)

FaseActorAcciónTouchpointEmoción [HIPÓTESIS]
1 HojearElenaAbre MARGEN; ve el número y las portadasHome lookbook + mastheadClaridad, “esto es un semanario”
2 ElegirElenaToca La merienda que no cabe en el grupoCard 16:10 → fichaReconocimiento del patio
3 LeerElenaKicker Patio, cuerpo, crédito Nuria/piezas/merienda-en-el-bancoCalma de lectura
4 ConsultarElenaAbre Agenda, anota Pradolongo sábado 11:00/agendaControl (sin “apuntarme”)
5 CompartirRaúlCopia el dato al grupoFuera de appAlivio
6 CerrarNuriaLogin, ve DRAFT, publica/mesa/mesa/nueva → okOficio, no euforia de “impreso”
7 ComprobarNuriaAbre home en incógnito: el DRAFT no está/ públicaConfianza

Momentos de verdad

  1. Portadas en el primer viewport — si hay que “descubrir la marca”, se rompe S2. [HIPÓTESIS]
  2. Agenda sin botón de reserva — si aparece “Inscribirse”, H2 falla.
  3. DRAFT invisible en público — prueba de “borrador ≠ publicado”.
  4. Success de mesa dice que no es imprimir — evita la mentira del tiraje.
  5. Masthead no esconde Agenda — Elena no busca un hamburger de 9 ítems. [HIPÓTESIS]

7. Service blueprint (resumen)

CapaElementos
Frontstage LECTORAMasthead, lookbook, ficha, agenda
Frontstage EDITORLogin, mesa, alta, success
BackstageCierre de número, foto del patio, mensaje del AMPA al grupo (fuera de app)
SistemasNest API :3017, Neon morning-truth-64427459, JWT, Angular galería
SoportesSeed 1 número + 4 piezas + 3 eventos + fotos, Paper, docs
Fallos0 piezas publicadas; 401 sin token; 404 slug DRAFT; red caída → UI error

Fallos de servicio y respuesta de diseño

FalloEvidencia de UIRecuperación
Número sin piezas publicadasUI-08 Empty lookbook“Este número aún no tiene piezas publicadas.”
Agenda vacíaUI-08 Empty agenda“Esta semana no hay citas en la agenda.”
Mesa vacíaUI-08 Empty mesa“Aún no hay piezas. Escribe la primera.”
API caídaUI-08 ErrorReintentar
Latencia lookbookUI-09 LoadingSkeleton de portada + 3 cards
Form inválidoInline fieldNo navegar a success
Intento de leer DRAFT por URL404“Esa crónica no está publicada.” [H3 / integridad]

8. Matriz hallazgo → requisito → feature

HallazgoTipoRequisitoFeature v1
Llega con “qué hay esta semana”[SUPUESTO] S2Lookbook es la homeUI-01 / H-GALLERY
PDF / WhatsApp no muestran portada[HIPÓTESIS] H1Cards 16:10 con leadGET current + covers
Agenda se lee como matrícula[HIPÓTESIS] H2Cero CTA de reservaUI-03 solo lectura
Borrador se filtra[SUPUESTO]Público = PUBLISHED404 en DRAFT
Digital ≠ kiosco[DECISIÓN]Copy irrenunciableSuccess + pie
Redacción 1–2 personas[SUPUESTO] S3Mesa = lista, no CMSUI-05 / UI-06
Lector no necesita cuenta[HIPÓTESIS] H3Auth solo EDITORLogin + guards API
L2 compacto, no enterprise[DECISIÓN]Un rol EDITOR; Issue seedSin cuenta LECTORA, sin CMS de tipos

9. Preguntas abiertas (no bloquean v1)

IDPreguntaCómo se resolvería después
Q1¿Archivo de números anteriores en home o en /archivo?L+1: índice por weekLabel; no search-first
Q2¿Un EDITOR o varios con byline distinto?authorUserId; v1 usa authorName libre
Q3¿Checkbox de “he leído que no es inscripción”?Innecesario si no hay form; legal L+1 si hubiera captura
Q4¿Despublicar vuelve a DRAFT o hay UNLISTED?[DECISIÓN v1] PATCH a DRAFT basta
Q5¿El Event pertenece al Issue por FK?Sí en modelo (issueId); GET /api/events filtra el current
Q6¿Horarios de piscina / biblioteca son oficiales?No. Seed demo. No se afirma como calendario municipal

10. Plan de research futuro (si hubiera campo real)

MétodoMuestra orientativaPregunta
Test de usabilidad lookbook5–6 madres/padres 30–50¿Encuentran “qué hay esta semana” en < 20 s?
Shadowing de cierre1 redacción 1–2 personas¿La mesa sustituye Drive + WhatsApp?
Revisión de expectativa de reservaClics en agenda vs “¿cómo me apunto?”Validar H2
Lectura mobile 3905 sesiones¿El cuerpo de crónica se lee de un tirón?

Estos métodos no se han ejecutado. No se reportan hallazgos como si lo hubieran sido.

11. Síntesis

MARGEN se diseña como semanario de barrio que se hojea y se publica, no como paywall, no como inscripción municipal y no como tabla de compromisos.
La investigación del caso es constructiva y etiquetada: personas, JTBD y journey son artefactos de diseño; las métricas de validación quedan para uso real futuro.

03-information-architecture.md

03 — Arquitectura de información — MARGEN

1. Principios de IA

PrincipioAplicación
Gallery firstLa home es el lookbook del número. No hay landing de marca por delante.
Hojear → leer → agendaProfundidad 2 desde la card hasta la crónica; agenda es hermana, no modal
Público vs EDITORLookbook, ficha y agenda abiertos; mesa solo autenticada
Lenguaje de dominioNúmero, pieza, kicker, agenda, mesa — no “post CMS”, “lead”, “SKU”, “plaza”
Borrador invisibleLa familia no ve DRAFT; 404 si adivina el slug
Agenda se leeEvento no tiene cupo, botón ni form (≠ PIZARRA)
Masthead siempre a manoS-TOP: wordmark + secciones; no rail, no dock

2. Sitemap

/                                      Lookbook del número (público)     H-GALLERY
/piezas/:slug                          Ficha de crónica (público si PUBLISHED)
/agenda                                Agenda familiar de la semana (público)
/login                                 Login JWT EDITOR
/mesa                                  Lista de piezas (auth EDITOR)
/mesa/nueva                            Alta de pieza (auth EDITOR)
/mesa/ok/:slug                         Success post-publicación (auth EDITOR)
/**                                    → redirect /

Árbol por audiencia

AudienciaNodos relevantes
LECTORA / AMPALookbook → Crónica → Agenda
EDITORLogin → Mesa → Nueva → Ok (y lookbook público para comprobar)
AmbosWordmark → / (EDITOR autenticada: Mesa en masthead)

[COMPROBADO] Siete rutas del encargo L2. No se inventan /inscribir, /suscribir, /comentarios, /archivo, /mesa/:id.

3. Navegación

Masthead (S-TOP)

SlotDestinoVisibilidadNotas
Wordmark MARGEN/TodosCormorant; no logotipo ilustrado
Número/TodosEstado activo en home
Agenda/agendaTodosCitas de la semana
Mesa/mesaEDITOR; si guest → /login?next=/mesaLista operativa
Entrar / Salir/login si guest; acción salir si authTodosAcceso EDITOR

[DECISIÓN] El masthead es la única navegación primaria. Tres destinos públicos + mesa. Encaja L2 compacto. No hay rail (CESTA), no dock (RONDA), no command search (PIZARRA).

Desktop ≥960px: cabecera horizontal, filete cadmio 2px bajo el masthead, secciones en Public Sans 14.
Mobile ~390px: wordmark + 2–3 links; Mesa se compacta a “Mesa” o icono de escritorio. [DECISIÓN] En 390 no se introduce hamburger de 9 ítems.

Pública (además del masthead)

ElementoDestinoNotas
Portada del número/ (ancla al grid) o primera piezaToda la portada 16:10 es clicable hacia la pieza lead o se queda como atmósfera del número
Card de pieza/piezas/:slugCover + kicker + título + lead
Enlace “Agenda de la semana”/agendaEn home, bajo el grid
Crédito / bylineno navegaTexto
Eventono navega a formBloque de lectura

[DECISIÓN] La portada del número no abre un /numeros/:id en v1: el número es la home. Un archivo de números sería L+1.

EDITOR (autenticado)

ElementoDestinoVisibilidad
Mesa/mesaEDITOR
Nueva pieza/mesa/nuevaEDITOR
Badge rolEDITOR
NombreNuria CeballosEDITOR
Salirlimpia token → /loginEDITOR
Publicaren form o en fila de mesaEDITOR · no hay /mesa/:id de ficha CMS

[DECISIÓN] L2: el PATCH vive en la fila de la mesa y/o al final del form de alta. No se añade /mesa/:id como Must.

4. Inventario de contenido

PantallaContenidos
Lookbook /Masthead, weekLabel, título del número, portada 16:10, grid ≥3 piezas (cover, kicker, título, lead), enlace agenda, empty, loading, error
FichaCover, kicker, título, byline, cuerpo, volver al número, enlace agenda
AgendaTitular de semana, 3 eventos (título, día/hora, lugar, público), disclaimer “se lee, no se reserva”
LoginTitular redacción, email, password, submit, error
MesaLista: kicker, título, status, updatedAt, acciones, CTA Nueva, empty, error
AltaCampos título, kicker, sección, cover (select seed), cuerpo, submit “Guardar borrador” + “Publicar”
SuccessMensaje, slug, “Publicar no es imprimir”, CTA ver pieza / volver a mesa

5. Taxonomía

PublishStatus (Issue y Piece)

Status APILabel UISemántica
DRAFTBorradorLa familia no lo ve
PUBLISHEDPublicadoVisible en lookbook y ficha

Orden de mesa: updatedAt descendente (lo último tocado primero).
[DECISIÓN] No hay SCHEDULED / REVIEW / KILLED: S3, mesa de 1–2.

PieceSection

APILabel UI (kicker)Seed
PATIOPatiomerienda-en-el-banco
COLEColepuerta-del-cole, lo-que-el-ampa-no-cuelga
BARRIOBarriovaso-de-agosto
LECTURALecturasilencio-y-patio

Issue (línea seed)

weekLabelTítuloCoverStatus
17–23 agoEl patio no cierra en agostohero.jpgPUBLISHED

Piece (líneas seed)

slugSecciónTítuloStatus
merienda-en-el-bancoPATIOLa merienda que no cabe en el grupoPUBLISHED
puerta-del-coleCOLEEl cole no ha abierto y el grupo ya está en llamasPUBLISHED
vaso-de-agostoBARRIOLa piscina de Orcasitas aguanta agostoPUBLISHED
silencio-y-patioLECTURALa biblioteca no es un PDFPUBLISHED
lo-que-el-ampa-no-cuelgaCOLELo que el AMPA no va a colgar en StoriesDRAFT

[COMPROBADO] Cuatro piezas + agenda de 3 y un DRAFT cubren el must del brief (demo: 1 número + 4 piezas + 3 eventos). El DRAFT extra es para que la mesa no sea una lista de solo publicados. [DECISIÓN]

EventAudience (texto libre en v1; valores seed)

Valor seedUso
FamiliasMerienda Pradolongo
Madres y padresCharla vuelta al cole
4 a 8 añosHora del cuento

No es un enum cerrado de producto: es copy. [DECISIÓN]

6. Modelo mental vs UI

Modelo mentalRepresentación
“¿Qué hay esta semana?”Home lookbook, título del número + grid
“La de la merienda”Card PATIO → ficha
“¿A qué hora es lo del sábado?”/agenda
“¿Me apunto?”No hay UI. Copy: se lee, no se reserva
“Lo estoy escribiendo”Badge Borrador en mesa
“Ya salió”Badge Publicado; aparece en /
“¿Sale en papel?”Success / pie: publicar ≠ imprimir
“El PDF del cole”Sustituido por la pieza COLE, no por un adjunto

7. Query string

L2 gallery-first no usa facetas de catálogo.
Único query admitido: /login?next=/mesa (redirect post-login).

[DECISIÓN] Sin ?q= ni chips de sección en home. Eso sería H-SEARCH (PIZARRA) o un archivo L+1.

8. Rutas API alineadas a IA

UIAPI
LookbookGET /api/issues/current
FichaGET /api/pieces/:slug
AgendaGET /api/events
LoginPOST /api/auth/login
Mesa listGET /api/mesa/pieces JWT
AltaPOST /api/pieces JWT
Publicar / despublicarPATCH /api/pieces/:id { status } JWT

[COMPROBADO] Contrato del encargo (Issue, Piece, Event, EDITOR). No se documentan comentarios, likes ni POST /api/events como Must.

9. Decisiones de IA descartadas

IdeaPor qué no en L2 v1
/explorar + lookbook secundarioRompe H-GALLERY
Área “mi revista” / bookmarksCuenta de facto; contradice H3
/mesa/:id ficha CMSL2 compacto; acciones en lista + form de alta
Search / chips de secciónH-SEARCH de PIZARRA
Mapa de meriendasH-MAP de DERIVA
Feed de “últimas del barrio”H-FEED de RONDA
Tabla de piezas como homeH-TABLE de CESTA
Wizard de 4 pasos de publicaciónF-ONB; el form es 1 pantalla
/inscribir/:eventIdRompe H2 / microcopy Agenda ≠ inscripción
/numeros/:week archivoL+1; el número en curso es la home

04-user-flows.md

04 — Flujos de usuario — MARGEN

Convenciones

  • Actor: Guest (LECTORA / AMPA) | EDITOR
  • Éxito: resultado observable
  • Errores: UI + código HTTP cuando aplica
  • Flujo canónico: F-STORY (hojear número → leer crónica → agenda)
  • Flujo de mesa: login → lista → alta → publicar

F1 — Descubrimiento por lookbook (LECTORA)

/  → lookbook del número (H-GALLERY)
   → GET /api/issues/current
   → portada 16:10 + ≥3 cards  |  empty  |  error  |  skeleton
   → click card → /piezas/:slug
   → masthead Agenda → /agenda
   → masthead Mesa / Entrar → /login  (si guest)
PasoAcciónSistema
1Aterriza; la portada del número (weekLabel + cover 16:10) es el primer focoRender home
2Recorre kicker, título y lead de cada piezaIssue + pieces PUBLISHED
3Abre crónicaRouter
4Masthead permanece visibleShell S-TOP

Éxito: al menos una ficha PUBLISHED alcanzable, o empty accionable.
AC: no hay que hacer scroll de “marca” para llegar a la primera portada. El recorte 16:10 deja ver el lead fotográfico (no un crop 1:1 que recorta cabezas).

Errores / estados

CasoComportamiento
0 piezas publicadasUI-08: “Este número aún no tiene piezas publicadas.”
Red / 5xxUI-08 + Reintentar
Primera cargaUI-09 skeleton de portada + 3 cards

F2 — Leer crónica (LECTORA)

/piezas/:slug → GET /api/pieces/:slug
              → cover, kicker, título, cuerpo, crédito
              → enlace Número → /
              → enlace Agenda → /agenda
              → 404 slug DRAFT o inexistente → mensaje + volver al número
PasoAcciónSistema
1Lee kicker y títuloPiece
2Lee cuerpo de un tirónPiece.body
3Ve crédito (authorName)Piece
4Decide otra pieza, agenda o homeRouter

Éxito: crónica leíble; crédito visible; no hay comentarios ni likes.
Error: 404 si slug inexistente o status=DRAFT.

AC ficha

#Criterio
1Foto real del cover (no color sólido)
2Kicker (Patio / Cole / Barrio / Lectura) sobre el título
3Título en Cormorant; cuerpo en Public Sans ≥16px
4Crédito “Nuria Ceballos” (o authorName) visible
5Sin CTA de inscripción, like o “suscríbete para seguir”

[DECISIÓN] Un DRAFT nunca hace 200 en esta ruta. No se “previsualiza” en público ni con query ?preview=. Preview = L+1 con token.


F3 — Agenda de la semana (LECTORA / AMPA)

/agenda → GET /api/events
        → 3 bloques (título, startsAt, place, audience)
        → disclaimer “Esto se lee; no es una inscripción.”
        → empty / error / skeleton
PasoAcciónSistema
1Lee la semana del númeroIssue.weekLabel + events
2Recorre día, lugar, públicoEvent
3Anota fuera de app (grupo, papel)Fuera

Éxito: 3 eventos visibles o empty honesto. Cero botones Inscribirse / Reservar / Apuntarme.

AC agenda

#Criterio
1Cada evento muestra título, fecha-hora, lugar, audiencia
2Disclaimer visible sobre el fold en desktop
3No hay <form> ni CTA primario de captura
4Horarios seed etiquetados como del número, no como “oficial Ayuntamiento”

[DECISIÓN] Tap en evento no abre ficha de reserva. Si en L+1 hubiera detalle, seguiría siendo lectura.


F4 — Login JWT (EDITOR)

/login → POST /api/auth/login { email, password }
      → 200 { accessToken, user } → localStorage → /mesa  (o ?next sanitizado)
      → 401 → mensaje error en form
CampoValidación clienteAPI
emailrequired, email@IsEmail()
passwordrequired, min 6@MinLength(6)

Éxito: token guardado; user role=EDITOR, nombre Nuria Ceballos.
Credencial demo: redaccion@margen.barrio / password123.

CasoComportamiento
Credenciales inválidas401 + mensaje
Red caídaError de red en UI
Token caducado en mesa401 en GET → re-login

F5 — Mesa de redacción (EDITOR)

/mesa (token en cliente)
  → GET /api/mesa/pieces
  → Render filas + badges DRAFT / PUBLISHED + CTA Nueva
CasoComportamiento
Lista con itemsFilas: kicker, título, status, updatedAt, acción Publicar si DRAFT
Lista vacíaEmpty: “Aún no hay piezas. Escribe la primera.”
Fallo red / 401Error + reintentar / re-login

[DECISIÓN] Sin stats endpoint en v1. Recuentos DRAFT/PUBLISHED, si se muestran, se derivan del array.


F6 — Alta de pieza (EDITOR)

/mesa/nueva
  → validación cliente
  → POST /api/pieces {
        title,
        kicker,
        body,
        cover,
        section,
        issueId,        // default: current issue
        authorName      // default: user.name
     }
  → 201 Piece { slug, status: DRAFT, ... }
  → o bien POST + PATCH { status: "PUBLISHED" } si elige Publicar
  → /mesa/ok/:slug
CampoValidación cliente (mín.)API
titlerequired, min 4@MinLength(4)
kickerrequired, min 2@MinLength(2)
bodyrequired, min 40@MinLength(40)
coverrequired, filename seed o URL relativaallowlist de assets
sectionrequired, enumPATIO | COLE | BARRIO | LECTURA
issueIddefault currentdebe existir
authorNamedefault user.name@MinLength(2)
statusno en POST; siempre DRAFT al crearservidor fuerza DRAFT

Éxito: registro status=DRAFT (o PUBLISHED si eligió Publicar en el mismo viaje) + pantalla success.
No hay cuenta de lectora en v1.

Errores

CasoComportamiento
Validación DTO400 + mensaje de campo
issueId inexistente400 / 404
Red caídaError de red en form; no navegar a /mesa/ok/…
Doble submitBotón disabled mientras pending
body < 40400
Sin token401

[DECISIÓN] Crear siempre como DRAFT. El botón Publicar del form hace POST + PATCH (o un flag publishNow aceptado por el servidor que no salta el estado intermedio en disco: persiste PUBLISHED, pero el contrato documentado es POST DRAFT → PATCH PUBLISHED). [DECISIÓN de implementación] ver doc 20.

[COMPROBADO] Entidades Piece = { title, kicker, body, cover, section, issueId, status, authorName } según encargo.


F7 — Publicar desde la mesa (EDITOR)

/mesa
  → PATCH /api/pieces/:id { status: "PUBLISHED" }
  → 200 Piece actualizado
  → opcional: /mesa/ok/:slug si se quiere el board de success

Transiciones (máquina simple L2)

DesdeHaciaIntención
DRAFTPUBLISHEDNuria cierra la crónica; entra al lookbook
PUBLISHEDDRAFTCorrección / retirada temporal
SCHEDULED / REVIEWNo en v1

Éxito: badge actualizado; la pieza aparece en GET /api/issues/current.
Errores: 404 id; 401 sin token; 400 status inválido.

Regla de integridad (ops): Publicar no crea un PDF, un tiraje ni un Event. Publicar ≠ imprimir. Agenda ≠ inscripción.


F8 — Success de publicación (EDITOR)

/mesa/ok/:slug → copy de acuse + título/slug
               → “Publicar no es imprimir.”
               → “La familia ya puede leerla. El kiosco no ha tirado nada.”
               → CTA ver pieza pública / volver a la mesa
PasoAcciónSistema
1Lee acuseUI
2Comprueba la pieza en incógnito (Could)Fuera / otra pestaña
3Sigue con la siguiente DRAFT/mesa

AC: el disclaimer es visible sin scroll en desktop.
Si se entra a /mesa/ok/algo-que-no-existe: mensaje genérico + volver a mesa; no se inventa un registro. [DECISIÓN]


F9 — Logout (EDITOR)

Click "Salir" (masthead) → limpia localStorage (token + user) → /login

Matriz de errores global

CódigoCuándoUI
400DTO inválidoMensaje campo / genérico
401Sin/mal token en mesaRe-login
404slug DRAFT, id o slug no existeMensaje + volver al número
5xx / networkAPI caídaError + retry

Flujos fuera de alcance v1

  • Registro / recuperación de password de EDITOR
  • Cuenta de lectora / bookmarks
  • Inscripción a Event
  • Notificación email “ha salido el número”
  • Filtros multi-criterio en mesa
  • Detalle /mesa/:id
  • Archivo de números
  • Comentarios / likes
  • Impresión / PDF de kiosco

05-data-model.md

05 — Modelo de datos — MARGEN

1. Visión general

Dominio L2 de semanario vecinal + mesa de publicación:

EntidadTabla SQLPropósito
UserusersIdentidad de redacción (rol EDITOR)
SessionsessionsSesión JWT / token persistido (Should)
IssueissuesNúmero semanal (portada, semana, estado)
PiecepiecesCrónica ligada a un número
EventeventsCita de agenda familiar ligada a un número

Base: PostgreSQL (Neon project morning-truth-64427459) · IDs: cuid() o entero serial.
[DECISIÓN] ensureSchema o Prisma son válidos si el contrato de tablas se cumple; el brief de stack no exige Prisma.

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

Role

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

PublishStatus

ValorDescripción
DRAFTInvisible en cara pública
PUBLISHEDVisible en lookbook / ficha / (si Issue) es el current

PieceSection

PATIO | COLE | BARRIO | LECTURA

3. Diagrama ER (texto)

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

sessions
  id, user_id → users
  token_hash, expires_at
  created_at

issues
  id, week_label (unique), title, cover, published_at
  status (DRAFT | PUBLISHED)
  created_at, updated_at
  1 ──< pieces
  1 ──< events

pieces
  id, slug (unique)
  issue_id → issues
  title, kicker, body, cover
  section (PATIO | COLE | BARRIO | LECTURA)
  status (DRAFT | PUBLISHED)
  author_name
  created_at, updated_at

events
  id
  issue_id → issues
  title, starts_at, place, audience
  created_at, updated_at

No hay FK entre pieces y users en v1: el byline es author_name texto. EDITOR opera sobre el conjunto global.

4. Tablas

users

CampoTipoConstraints
idTEXTPK
emailTEXTUNIQUE NOT NULL
password_hashTEXTNOT NULL (bcrypt)
nameTEXTNOT NULL
roleTEXTNOT NULL DEFAULT 'EDITOR'
created_atTIMESTAMPTZDEFAULT now()
updated_atTIMESTAMPTZDEFAULT now()

sessions

CampoTipoConstraints
idTEXTPK
user_idTEXTNOT NULL FK → users(id) ON DELETE CASCADE
token_hashTEXTNOT NULL
expires_atTIMESTAMPTZNOT NULL
created_atTIMESTAMPTZDEFAULT now()

[DECISIÓN] El JWT viaja en Authorization: Bearer. sessions permite invalidar (logout) sin esperar expiración. Si el slice usa JWT stateless, documentar el hueco; D-P1-05 se cumple igual con guard.

issues

CampoTipoConstraints
idTEXTPK
week_labelTEXTUNIQUE NOT NULL (17–23 ago)
titleTEXTNOT NULL
coverTEXTfilename (hero.jpg)
published_atTIMESTAMPTZNULL si DRAFT
statusTEXTNOT NULL DEFAULT 'DRAFT'
created_at / updated_atTIMESTAMPTZ

[DECISIÓN] GET /api/issues/current = el Issue PUBLISHED con published_at más reciente. En demo hay uno.

pieces

CampoTipoConstraints
idTEXTPK
slugTEXTUNIQUE NOT NULL, kebab-case
issue_idTEXTFK Issue NOT NULL
titleTEXTNOT NULL
kickerTEXTNOT NULL
bodyTEXTNOT NULL (markdown simple o HTML escapado)
coverTEXTfilename (merienda.jpg …)
sectionTEXTNOT NULL (PATIO | COLE | BARRIO | LECTURA)
statusTEXTNOT NULL DEFAULT 'DRAFT'
author_nameTEXTNOT NULL
created_at / updated_atTIMESTAMPTZ

lead no se persiste: se deriva del primer párrafo de body (~160 caracteres) para las cards. [DECISIÓN]

events

CampoTipoConstraints
idTEXTPK
issue_idTEXTFK Issue NOT NULL
titleTEXTNOT NULL
starts_atTIMESTAMPTZNOT NULL
placeTEXTNOT NULL
audienceTEXTNOT NULL
created_at / updated_atTIMESTAMPTZ

Sin seats, enrolled, status. Agenda ≠ inscripción. [COMPROBADO]

5. Reglas de integridad y negocio

ReglaImplementación
Lectura pública de númeroGET /api/issues/current sin guard; solo PUBLISHED + pieces PUBLISHED
Lectura pública de piezaGET /api/pieces/:slug 200 solo si PUBLISHED; DRAFT → 404
Agenda públicaGET /api/events del current issue; sin form
List / create / patch piezasJWT EDITOR → 401 sin token
Slug únicokebab del título + sufijo -2 si colisión [DECISIÓN]
Status default piezaDRAFT al crear
PasswordNunca en claro; solo password_hash
Orden lookbookestable: seed order o created_at asc (el número se hojea, no se “destaca” por likes)
Orden mesaupdated_at desc
Orden agendastarts_at asc
Publicar Issueno Must de UI v1 (Issue va seed PUBLISHED)
Publicar Pieceno crea Event ni PDF
Público nunca lista DRAFTGET current filtra; no hay ?includeDrafts

6. Contratos API (resumen)

GET /api/issues/current (público)

Response 200: Issue + pieces: PieceCard[] (solo PUBLISHED):

{
  "id": "issue_w33",
  "weekLabel": "17–23 ago",
  "title": "El patio no cierra en agosto",
  "cover": "hero.jpg",
  "publishedAt": "2026-08-17T05:00:00.000Z",
  "status": "PUBLISHED",
  "pieces": [
    {
      "slug": "merienda-en-el-banco",
      "title": "La merienda que no cabe en el grupo",
      "kicker": "Patio",
      "section": "PATIO",
      "cover": "merienda.jpg",
      "lead": "Familias se sientan en el banco de piedra…",
      "authorName": "Nuria Ceballos",
      "status": "PUBLISHED"
    }
  ]
}

JSON camelCase hacia el web. [DECISIÓN]
Si no hay Issue PUBLISHED: 404 o 200 con { pieces: [] } + empty de home. [DECISIÓN] 200 + empty es más amable para UI-08.

GET /api/pieces/:slug (público)

Piece completa (body) o 404 (inexistente o DRAFT).

GET /api/events (público)

Response 200: Event[] del current issue, startsAt asc.

{
  "id": "evt_merienda",
  "title": "Merienda de patio en Pradolongo",
  "startsAt": "2026-08-22T09:00:00.000Z",
  "place": "Parque de Pradolongo, Usera",
  "audience": "Familias"
}

POST /api/auth/login

Body: { email, password }
Response 200: { accessToken, user: { id, email, name, role } }

GET /api/mesa/pieces (JWT)

Array Piece (sin necesidad de body largo; incluir status), updatedAt desc. Sin token → 401. Incluye DRAFT.

POST /api/pieces (JWT)

Body

CampoTipoReq
titlestring
kickerstring
bodystring
coverstring
sectionPieceSection
issueIdstringno (default current)
authorNamestringno (default user.name)

Response 201: Piece + slug + status: "DRAFT".

PATCH /api/pieces/:id (JWT)

Body: { status?: PublishStatus, title?, kicker?, body?, cover?, section?, authorName? }
Mínimo Must: { status }.
Response: Piece actualizada. Sin token → 401.

[COMPROBADO] PATCH sobre :id con { status }.

7. Seed de referencia (2026-08-17)

EDITOR

NombreEmailPassword
Nuria Ceballosredaccion@margen.barriopassword123

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

Issue

weekLabelTítuloCoverStatuspublishedAt
17–23 agoEl patio no cierra en agostohero.jpgPUBLISHED2026-08-17 07:00 Europe/Madrid

Pieces

slugSecciónTítuloCoverStatus
merienda-en-el-bancoPATIOLa merienda que no cabe en el grupomerienda.jpgPUBLISHED
puerta-del-coleCOLEEl cole no ha abierto y el grupo ya está en llamascolegio.jpgPUBLISHED
vaso-de-agostoBARRIOLa piscina de Orcasitas aguanta agostopiscina.jpgPUBLISHED
silencio-y-patioLECTURALa biblioteca no es un PDFbiblioteca.jpgPUBLISHED
lo-que-el-ampa-no-cuelgaCOLELo que el AMPA no va a colgar en Storiescolegio.jpgDRAFT

Textos de body / lead son contenido de producto demo, no reportaje de un diario real. [SUPUESTO de catálogo]

slugLead demo (primeros ~160)
merienda-en-el-bancoEn el banco de piedra del patio de manzana hay Fanta, bolsas de pan y un casco de moto. Agosto no se ha ido. El grupo del cole, sí: nadie pegó la foto.
puerta-del-coleLas mochilas ya cuelgan de la valla y el cole aún no ha abierto. El hilo del AMPA lleva tres PDFs y ninguna hora buena.
vaso-de-agostoEl vaso de Orcasitas sigue en azul bajo los bloques. Quedan tardes. No es un chiringuito: es la piscina que hay.
silencio-y-patioLa sala da al patio y el cartel dice Biblioteca Municipal. El silencio no es un PDF. Hay sillas de enea y una pila de cuentos.
lo-que-el-ampa-no-cuelgaBorrador: lo que Raúl no va a poner en Stories — horarios, no poses. Invisible en home.

Events

TítulostartsAt (Europe/Madrid)LugarPúblico
Merienda de patio en Pradolongo2026-08-22 11:00Parque de Pradolongo, UseraFamilias
Charla de vuelta al cole2026-08-18 18:00AMPA · local demo CarabanchelMadres y padres
Hora del cuento de agosto2026-08-19 17:30Biblioteca municipal, Villaverde4 a 8 años

Los tres eventos son seed de producto. No se presentan como calendario oficial de un distrito, un CEIP o una biblioteca concreta. [SUPUESTO de catálogo]

8. Evolución posible (no implementada)

CambioNivel
Archivo de Issues + /numeros/:weekL+1
authorUserId + varios EDITORESL+1 / L3
Preview token de DRAFTL+1
CMS de Event autenticadoL+1
Soft delete + audit log de statusL3
Comentarios / likesFuera (S4)
Cupo / inscripción en EventFuera (H2)

06-tech-stack.md

06 — Stack tecnológico — MARGEN

1. Visión

CapaTecnologíaNotas
FrontendAngular standalone + signalsPuerto 4200
EstilosTailwind CSSTokens gallery (papel/tinta/cadmio/grafito/pliego/filete)
BackendNestJS TypeScriptPuerto 3017, prefijo /api
PersistenciaPostgreSQL (ensureSchema o Prisma)Tablas users, sessions?, issues, pieces, events
DBNeon PostgreSQLproject morning-truth-64427459
AuthJWTRol EDITOR
DiseñoPaper01M078GFW7QQF5RRA2XGKQ8BD9
Repo/Users/cristian/orca/margen-app/GitHub Criscode2022/margen-app

Stack fijo del cron (D-P0-03). No React/Next/Firebase.
[COMPROBADO] Puerto 3017, Neon, Paper y repo constan en el encargo.

2. Estructura

margen-app/
├── apps/api/     # Nest (paquete independiente)
├── apps/web/     # Angular + Tailwind (paquete independiente)
└── package.json  # scripts api / start · apps independientes

D-P1-03: npm --prefix o pnpm --filter. Prohibido npm workspaces que rompen Angular (AP-06).

Scripts raíz esperados:

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

3. API pública vs JWT

MétodoRutaAuth
GET/api/issues/currentPúblico
GET/api/pieces/:slugPúblico (404 si DRAFT)
GET/api/eventsPúblico
POST/api/auth/loginPúblico
GET/api/mesa/piecesJWT EDITOR
POST/api/piecesJWT EDITOR
PATCH/api/pieces/:idJWT EDITOR

CORS: origen http://localhost:4200 en local.

[COMPROBADO] Superficie API del encargo. No se añaden Must extra (/comments, POST /events, /subscribe).

4. Justificación

ElecciónRazón
Angular + NestAlineación con la serie daily y el handoff del estudio
Neon serverlessVolumen bajo (S1: 1 número + 4–8 piezas; demo 4+1); no cola Redis
JWT EDITORD-P1-05: panel interno cerrado desde el día 1
Filtro PUBLISHED en servidorSource of truth = SQL; la home no “esconde” DRAFT en cliente
Puerto 3017Evitar colisión con CESTA :3016 / RONDA :3015 / DERIVA :3014 / PIZARRA :3013

5. Variables

.env local (nunca git):

VariableServicioDescripción
DATABASE_URLAPINeon morning-truth-64427459
JWT_SECRETAPIFirma tokens
PORTAPIopcional, 3017
JWT_EXPIRESAPIopcional (p. ej. 12h)

.env.example solo placeholders.
Web: URL de API en ApiService (default http://localhost:3017/api).

6. Dependencias de producto (mínimas)

API

  • @nestjs/common / core / platform-express
  • @nestjs/jwt (o verificación manual)
  • bcrypt (o bcryptjs)
  • cliente Postgres (pg) o Prisma
  • class-validator + class-transformer

Web

  • Angular standalone
  • Tailwind 3
  • fuentes: Cormorant Garamond + Public Sans (Google Fonts o self-host)

7. Arranque (contrato)

cd /Users/cristian/orca/margen-app
# instalar apps independientes (npm --prefix o pnpm --filter)
# apps/api/.env → DATABASE_URL + JWT_SECRET + PORT=3017
# migrate / ensureSchema + seed
# api → http://localhost:3017
# web → http://localhost:4200

8. Lo que este stack no es

NoPor qué
npm workspacesAP-06
Firebase AuthStack fijo JWT + Neon
Next.js / ReactD-P0-03
Pasarela de pago / paywallS2 / H3
Elasticsearch4 piezas no lo necesitan
CMS headless (Strapi / Sanity)S3: mesa de 1–2, no tipos

9. Nota sobre el repo existente

[COMPROBADO] Existe /Users/cristian/orca/margen-app y el remoto previsto Criscode2022/margen-app.
El scaffold contiene leftover de otros productos (walks, requests, fotos de despensa CESTA en public/assets/needs/). Esta suite define el contrato MARGEN; el código debe alinearse a las rutas y API de los docs 03–05, no al leftover. [DECISIÓN]

07-creative-direction.md

07 — Dirección creativa — MARGEN

1. Concepto

MARGEN es un kiosco de barrio en pantalla: semanario que se hojea, no una landing de “medio digital”. El ground es papel blanco de galería. Las portadas se cuelgan como en un expositor. El cadmio es la mancha de rotativa, no un botón de marketing.

Mood elegido: gallery / newsstand.
Primer instinto descartado: bookish plaster × ink (capilla, enyesado, vela). Ese mood ya huele a revista literaria de centro. MARGEN es patio, valla del cole y vaso municipal.

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

2. Territorio visual

EjeNo
SuperficieBlanco de kiosco, filete fino, card pliegoMusgo CESTA, cromo RONDA, agua DERIVA, hielo PRIMA, chalky PIZARRA
TipoCormorant Garamond display + Public Sans UINewsreader, Outfit, Spectral, Manrope, Zilla, Mulish, Lora, Karla
FotoBarrio sur realista, mediodía, ropa tendida, mochilasStock de familia feliz, skyline, “diversity lunch”
GridLookbook 16:10, 1 portada + 3 cardsHero 2-col + 3 cards de features (AP-12)
AcentoCadmio #C41E3A en filete y PUBLISHEDNaranja ONG, teal seguro, wine atelier
ChromeMasthead de periódicoRail de iconos, dock, sidebar CMS

3. Paleta

TokenHexRol
Papel / G-GALLERY#FFFFFFGround de página. Kiosco, no “off-white sucio”.
Tinta#16141ATexto, wordmark, cuerpo. Casi negro, no púrpura.
Cadmio#C41E3AFilete de masthead, acento, badge PUBLISHED, CTA de mesa
Grafito#5C5866Kicker, meta, nav idle, crédito
Pliego#F4F1EASolo cards (pieza, evento). Nunca el fondo de página.
Filete#E8E4DCRules, bordes, skeletons

Jerarquía de color: el blanco carga; el cadmio puntúa; el pliego encuadra la foto. Si el cadmio pinta fondos enteros, deja de ser rotativa y se vuelve “brand red”. [DECISIÓN]

4. Tipografía

UsoFamiliaTamaños de referencia
WordmarkCormorant Garamond 60028–32 desktop · 24 mobile
Título de númeroCormorant Garamond 60040–56
Título de crónicaCormorant Garamond 60036–48 desktop · 32 mobile
Lead / entradillaCormorant Garamond 400 italic o Public Sans 40018–20
Cuerpo de crónicaPublic Sans 40017–18 / 28–30 lh
UI, nav, form, agendaPublic Sans 400/500/60014 / 16
KickerPublic Sans 60012–13, tracking 0.08em, uppercase, cadmio o grafito

Prohibido: Cormorant por debajo de 20px (se rompe). Public Sans en el wordmark (se vuelve startup).

5. Fotografía

Las cinco imágenes del case son el sistema, no un moodboard:

AssetLectura visualUso
hero.jpgSemanario abierto, café, cuaderno de cuadros, luz de ventanaPortada del número · cover UX
merienda.jpgPatio de manzana, banco de piedra, merienda, ropa tendidaPieza Patio
colegio.jpgCEIP de ladrillo, plátanos, mochilas en la vallaPieza Cole
piscina.jpgVaso municipal, hamacas, bloques de ladrilloPieza Barrio
biblioteca.jpgSala con patio, sillas de enea, cartel municipalPieza Lectura

Crop: cards y portada en 16:10. El lead fotográfico (caras en el banco, mochilas, lámina de agua, mesa de lectura) debe quedar dentro del recorte. [COMPROBADO] Must del brief.

Tratamiento: saturación real, sin LUT “editorial teal-orange”, sin grano falso de película. El cadmio no se superpone como filtro: vive en UI.

6. Layout

Masthead (S-TOP)

MARGEN                         Número    Agenda    Mesa
17–23 ago · Usera · Carabanchel · Villaverde
────────────────────────────────────────────  (filete cadmio 2px)

Wordmark a la izquierda. Secciones a la derecha. Línea de distrito en Public Sans 12 grafito. Filete cadmio. No hamburger en desktop.

  1. Bloque de número: weekLabel + título en Cormorant + portada 16:10 (hero.jpg).
  2. Grid de piezas: 3 columnas desktop / 1 mobile. Card pliego: foto 16:10 + kicker + título + lead.
  3. Cierre: enlace a Agenda, no un form.

La portada no comparte fila con un muro de copy (“Cómo funciona MARGEN”). Eso sería H-HERO2 / AP-12.

Ficha

Cover a ancho de columna de lectura (~680px), no full-bleed de marketing. Kicker → título → byline → cuerpo. Blancos verticales de semanario, no de landing.

Mesa

Lista densa sobre papel. No imita el lookbook. Es trastienda: filas, badges, CTA cadmio. El EDITOR no necesita “inspiración de marca” para publicar.

7. Motion

SuperficieSpec
Hover cardFilete grafito; no elevación 8px ni scale 1.04
Cambio de páginaFade 160ms o ninguno
SkeletonPulso 1.2s en filete; off si reduced-motion
PublicarBadge, no confetti ni “rotativa animada”

Prohibido: parallax en portada, scroll-jacking, page transitions de 400ms, sticker de “NEW” parpadeante.

8. Anti-clichés (serie ALS-2)

ClichéPor qué no
Bookish plaster × inkPrimer instinto del brief; vetado
Wine + blush atelier (PLIEGO)Moda, no barrio
Botanical / musgo (CESTA)Despensa
Chrome / neón (RONDA)Gaming
Chalky municipal (PIZARRA)Inscripción
Familia stock con globosMentira social del “barrio feliz”
Paywall blur + “suscríbete”Rompe S2
Iconos outline de periódico 2014Masthead tipográfico basta

9. Tono de marca (visual + verbal, puente a doc 09)

Cercano de kiosco, concreto, de patio. Tuteo. Segunda persona cuando habla la UI. Tercera cuando habla la crónica.

El producto se hojea y se publica. No vende una comunidad, no pide plaza, no pide dinero.

10. Criterios de aceptación creativos

  1. Ground de página = #FFFFFF. Cards = #F4F1EA. Nunca al revés.
  2. Filete cadmio bajo el masthead, 2px, no un header rojo lleno.
  3. ≥3 portadas/piezas con recorte 16:10 visible en el primer viewport desktop.
  4. Ninguna fuente de la lista vetada (Newsreader / Outfit / Spectral / Manrope / Zilla / Mulish / Lora / Karla).
  5. Home reconocible como kiosco, no como hero 2-col de startup.
  6. Success de mesa no celebra un “número impreso”.

08-design-system.md

08 — Design system — MARGEN

1. Tokens

--color-paper:    #FFFFFF;   /* G-GALLERY ground */
--color-ink:      #16141A;
--color-cadmium:  #C41E3A;
--color-graphite: #5C5866;
--color-pliego:   #F4F1EA;   /* cards only */
--color-rule:     #E8E4DC;
--color-draft:    #5C5866;   /* badge DRAFT */
--color-live:     #C41E3A;   /* badge PUBLISHED */

--font-display: "Cormorant Garamond", Georgia, serif;
--font-ui:      "Public Sans", system-ui, sans-serif;

--radius-card: 0;            /* corte de kiosco, no pill */
--radius-cta:  2px;
--rule-mast:   2px solid var(--color-cadmium);
--space:       4 / 8 / 12 / 16 / 24 / 32 / 48 / 64;

Tailwind (referencia):

KeyValor
colors.paper#FFFFFF
colors.ink#16141A
colors.cadmium#C41E3A
colors.graphite#5C5866
colors.pliego#F4F1EA
colors.rule#E8E4DC
fontFamily.displayCormorant Garamond
fontFamily.sansPublic Sans

[COMPROBADO] Hex y tipo = brief.

2. Escala tipográfica

TokenFamiliaSize / lhUso
display-xlCormorant 60056 / 60Título de número desktop
display-lCormorant 60040 / 44Título de número mobile · título crónica desktop
display-mCormorant 60032 / 36Título crónica mobile · wordmark
leadPublic Sans 40018 / 28Entradilla de card
bodyPublic Sans 40017 / 28Cuerpo de crónica
uiPublic Sans 40016 / 24Form, agenda, lista mesa
metaPublic Sans 50013 / 18Fecha, lugar, crédito
kickerPublic Sans 60012 / 16 · tracking 0.08em · uppercaseSección

3. Componentes

Masthead

SpecValor
Alto desktop72–88px + línea de distrito 24px
Alto 39056px + links 44px
FondoPapel
Rule2px cadmio full-bleed
LinksPublic Sans 14 · tinta activo · grafito idle
Activoaria-current="page" + filete 2px cadmio bajo el label

Slots: Número / · Agenda /agenda · Mesa /mesa · Entrar /login o Salir.

Card de pieza (lookbook)

┌─────────────────────────────┐
│ cover 16:10                 │
│                             │
├─────────────────────────────┤
│ KICKER                      │
│ Título en Cormorant         │
│ Lead 2–3 líneas Public Sans │
└─────────────────────────────┘
  • Fondo pliego, sin sombra.
  • Toda la card es un <a>.
  • Hover: rule 1px grafito. Sin lift.
  • Imagen object-fit: cover anclada al centro-arriba para no cortar caras.

Portada de número

  • Ratio 16:10 obligatorio (must brief).
  • Overlay opcional: weekLabel + título en papel sobre cadmio al 0% — preferible título fuera de la foto, debajo, para no pelear con hero.jpg. [DECISIÓN] Título bajo la foto.

Ficha de crónica

BloqueSpec
Columnamax-width 680px, centrada
Cover16:10, full de columna
Kickercadmio o grafito, sobre el título
Títulodisplay-l / display-m
Byline“Nuria Ceballos · 17 ago” meta
Cuerpobody 17/28 · max 70ch
Volverlink “← El número” no breadcrumb de 5 niveles

Evento (agenda)

Fila o card pliego con cuatro campos en este orden: cuándo · título · dónde · para quién.
Disclaimer de bloque, no de cada fila: “La agenda se lee. No es una inscripción.”

Fila de mesa

ColumnaContenido
KickerPATIO / COLE / …
Título1 línea, truncate
StatusBadge Borrador / Publicado
updatedAtmeta, Europe/Madrid
AcciónPublicar (si DRAFT) · ver

Badge DRAFT: texto grafito, rule filete.
Badge PUBLISHED: texto cadmio o papel sobre cadmio ≥14 bold.

Botones

VarianteUsoSpec
PrimaryPublicar, Entrar, Guardar y publicarFondo cadmio, texto papel, h-44, radius 2
SecondaryGuardar borrador, VolverRule tinta, texto tinta, fondo papel
GhostSalir, ReintentarTexto grafito
DangerNo hay borrado Must

Pending: disabled + aria-busy. No spinner de marca.

Form

Labels visibles (no placeholder-only). Inputs h-44, radius 2, rule filete, foco outline 2px cadmio offset 2. Textarea cuerpo min 8 filas. Select de section y cover (allowlist de assets).

Estados

EstadoReceta
EmptyTitular Cormorant 32 + 1 línea Public Sans + (mesa) CTA Nueva
ErrorBanner filete cadmio + texto + Reintentar
LoadingSkeleton portada 16:10 + 3 cards pliego; mesa: 5 filas filete
404 pieza“Esa crónica no está publicada.” + link al número

4. Grid y breakpoints

ViewportComportamiento
≥1200Portada 16:10 ancha; grid piezas 3 col; mesa tabla
960–1199Grid 2 col; mesa tabla
600–959Portada full; grid 1–2; mesa lista
~390 (UI-10)Portada full; 1 col; cuerpo 17px; masthead compacto; mesa apilada

Padding horizontal: 24 desktop, 16 mobile.
Main en 390: padding-bottom 24 (no hay rail inferior).

5. Iconografía

Mínima. El semanario no es un set de iconos outline.

SitioRecurso
MastheadTexto. Sin icono de “home”.
EmptyNada o una rule cadmio de 32px
StatusTexto de badge, no semáforo

Si hace falta un icono (salir, error): trazo 1.5, 20px, tinta. No pack Remix/Lucide a color.

6. Elevación y borde

SuperficieTratamiento
PáginaPapel plano
CardPliego plano + (opcional) rule 1px filete
MesaFilas separadas por rule filete
ModalNo hay modal Must (confirmación de despublicar = Should)

Cero sombras shadow-lg. El kiosco no flota.

7. Mapa componente → ruta

ComponenteRutas
MastheadComponenttodas
IssueCover/
PieceCard/
PieceArticle/piezas/:slug
EventRow/agenda
DeskRow/mesa
PieceForm/mesa/nueva
EmptyState / ErrorBanner / SkeletonGallery/, /agenda, /mesa

8. Criterios de aceptación DS

  1. Tokens Tailwind = hex del brief, sin “casi blanco” #FAFAFA como ground.
  2. Cards en pliego; página en papel.
  3. Primary CTA nunca en grafito sobre filete (contraste).
  4. Cormorant no aparece en labels de form ni en badges.
  5. Recorte 16:10 implementado como aspect-[16/10], no 4:3 ni 1:1.
  6. Targets de masthead y CTA ≥44px.

09-content-guide.md

09 — Guía de contenido — MARGEN

1. Voz

Cercana de kiosco y de patio. Tuteo en UI. Segunda persona cuando la interfaz habla. Tercera cuando habla la crónica.

Sin jerga de medios (“contenido premium”, “engagement”, “comunidad de lectores”). Sin sede electrónica. Sin “únete a la conversación”.

El producto se hojea y se publica. No vende una causa, no pide plaza, no pide dinero.

2. Palabras permitidas / prohibidas

UsarNo usar
Número / semanarioEdición impresa, tiraje, “ya está en kiosco” (si es solo digital)
Pieza / crónicaPost, artículo CMS, contenido, story (de feed)
Kicker / Patio · Cole · Barrio · LecturaCategoría, tag, vertical, “sección lifestyle”
Agenda / citaInscripción, reserva, plaza, cupo, WAITLIST
Publicar / publicadoImprimir, mandar a rotativa, “sale el papel”
BorradorPending review, staging, “oculto al algoritmo”
Mesa / redacciónInbox, CRM, backoffice, CMS
Lectora / familiaUsuario, lead, suscriptora
EditoraCommunity manager, content owner
Se leeApúntate, reserva tu sitio

3. Microcopy duro (literales irrenunciables)

El brief fija tres oposiciones. Aparecen donde el usuario puede confundirse.

OposiciónDóndeCopy
Publicar ≠ imprimirSuccess de mesa · pie de número“Publicar no es imprimir. El número digital no es el tiraje de kiosco.”
Borrador ≠ publicadoMesa · 404 de slug DRAFT“Borrador: la familia no lo ve.” / “Esa crónica no está publicada.”
Agenda ≠ inscripción/agenda sobre el fold“La agenda se lee. No es una inscripción.”

[DECISIÓN] Los tres textos son obligatorios en UI. No se diluyen a un tooltip.

4. Microcopy por superficie

SuperficieCopy
EsloganLa semana del barrio, en un número.
Línea de distritoUsera · Carabanchel · Villaverde
Home, bajo títuloNúmero del 17 al 23 de agosto.
Card CTA implícitoToda la card es el enlace; no “Leer más”
Ficha volver← El número
Agenda titularAgenda de la semana
Agenda disclaimerLa agenda se lee. No es una inscripción. Si hay lista, se hace en el patio.
Empty lookbookEste número aún no tiene piezas publicadas.
Empty agendaEsta semana no hay citas en la agenda.
Empty mesaAún no hay piezas. Escribe la primera.
ErrorNo hemos podido cargar el número.
Error retryReintentar
Login titularRedacción
Login submitEntrar
Login errorEmail o contraseña no valen.
Mesa titularMesa
Mesa CTANueva pieza
PATCH PUBLISHEDPublicar
PATCH DRAFTVolver a borrador
Alta títuloNueva pieza
Alta submit secundarioGuardar borrador
Alta submit primarioPublicar
Success titularPublicada.
Success cuerpoLa familia ya puede leerla. Publicar no es imprimir. El kiosco no ha tirado nada.
404 DRAFTEsa crónica no está publicada.
Masthead NúmeroNúmero
Masthead AgendaAgenda
Masthead MesaMesa
SalirSalir

5. Crónicas seed (tono)

Las piezas demo se escriben como crónica de barrio, no como nota de gabinete ni como columnismo de centro.

PiezaTono
MeriendaObservación: banco, Fanta, casco, ropa tendida. Sin moraleja.
ColeEl grupo echa humo; el PDF no basta. Sin atacar a un CEIP real por nombre.
PiscinaEl vaso que hay, los bloques, agosto que se acaba. Sin “escapada”.
BibliotecaSala, patio, silencio. El cartel municipal es atrezzo, no fuente oficial.
DRAFT AMPAOficio: lo que no va a Stories. Invisible en home.

No inventar declaraciones de vecinas reales. Si hay una voz, es de la narradora (Nuria) o de persona de diseño etiquetada.

6. Nombres propios del seed

NombreUso
Elena VargasLECTORA; no deja PII en producto
Nuria CeballosEDITOR; byline; redaccion@margen.barrio
Raúl MéndezAMPA; aparece en copy de DRAFT, no como cuenta
Hugo / InésHijos de Elena; no son UI

No inventar CIF, director de CEIP, ni horarios oficiales. [SUPUESTO de catálogo demo]
Franjas demo: sábado 11:00 merienda · lunes 18:00 charla · miércoles 17:30 cuento. No se afirman como agenda municipal.

7. Tono por estado (mesa)

StatusFrase mesaFrase que Nuria podría decir (fuera de app)
DRAFTLa familia no lo ve“Aún no. Está en la mesa.”
PUBLISHEDEn el número“Ya está. No, no sale en papel.”

La app no envía esos mensajes en v1. El copy solo prepara el habla.

8. Capitalización y números

  • Wordmark: MARGEN en versales Cormorant.
  • weekLabel: 17–23 ago (en-dash, mes abreviado minúscula).
  • Fechas de agenda: sáb 22 ago · 11:00 (punto medio, 24h).
  • Distritos: Usera, Carabanchel, Villaverde (con mayúscula).
  • No mezclar “agosto 17-23” estilo US.

9. Idioma

es-ES. Fácil lectura. EN no en v1.
No mezclar “piece” en UI. En API sí: pieces, issueId.

10. Accesibilidad de copy

  • No transmitir estado solo con color (“el rojo significa publicado”).
  • Badge lleva texto: Borrador, Publicado.
  • Alt de fotos: descriptivo del barrio, no “imagen1”.
    • hero: “Semanario abierto en una mesa, café y cuaderno de cuadros.”
    • merienda: “Familias merendando en un banco de piedra de un patio de manzana.”
    • colegio: “Puerta de un colegio de ladrillo, mochilas colgadas en la valla.”
    • piscina: “Piscina municipal con bloques de viviendas al fondo.”
    • biblioteca: “Sala de lectura municipal con mesa de madera y patio al fondo.”

11. Piezas que no se escriben

NoMotivo
“Suscríbete para seguir leyendo”S2 / H3
“Reserva tu plaza” / “Apúntame”H2 · Agenda ≠ inscripción
“Ya está en el kiosco” como hecho de publicación digitalPublicar ≠ imprimir
Ranking de las más leídasLikes, otro producto
Lorem / “lorem ipsum merienda”Prohibido en el case
Declaraciones inventadas de un CEIP o biblioteca realesVerdad de catálogo

10-accessibility.md

10 — Accesibilidad · MARGEN

Objetivo: WCAG 2.2 AA.

ÁreaDecisión
ContrasteTinta #16141A sobre #FFFFFF ≥ 12:1. Cadmio #C41E3A sobre blanco ≥ 5:1 en texto ≥14px bold.
FocoAnillo 2px ink. Orden: masthead → nav → galería → pie.
Imágenesalt = título de la pieza. Hero decorativo alt="".
TextoCuerpo ≥ 16px / 26px. Kicker no es el único medio de sección.
TecladoCards son <a>. Mesa: filas con enlace de título.
MovimientoSin autoplay. prefers-reduced-motion corta hover scale.
Idiomalang="es".
FormulariosLabels visibles. Error junto al campo.
SemánticaUn h1 por página (masthead visual + h1 de pieza).

No conforme (fuera L2): subtítulos de vídeo (no hay vídeo). PDF accesible del número (no hay PDF).

11-privacy-security.md

11 — Privacidad y seguridad · MARGEN

Datos

DatoDóndeBase
Email redacciónusersContrato interno
Piezaspieces (cuerpo público si PUBLISHED)Interés informativo local
Eventosevents (horarios públicos)Interés informativo

No se pide cuenta a la lectora. No hay tracking de menores. No se recogen fotos de niños identificables en el seed.

Seguridad L2

  • JWT + sesión en Neon. Bcrypt 12.
  • DRAFT nunca en GET /pieces.
  • Rate limit en /auth/login.
  • CORS acotado al front.
  • Secretos solo en .env (no git).

No se declara cumplimiento RGPD definitivo. Sí: minimización y derecho a borrar cuenta de editora (manual L2).

12-analytics.md

12 — Analítica · MARGEN

North star: piezas leídas / semana (evento piece_open, umbral 30s).

EventoCuándo
home_viewCarga del lookbook
piece_openApertura de crónica
agenda_viewVista de agenda
editor_loginJWT ok
piece_publishDRAFT → PUBLISHED

No hay funnel de suscripción. No se mide “likes”. Hipótesis H2: agenda_view sin signup_click (no existe CTA).

13-qa-test-plan.md

13 — Plan de pruebas — MARGEN

1. Smoke obligatorio (D-P1-06)

#AcciónEsperado
1GET /api/issues/current200 · weekLabel 17–23 ago · pieces.length ≥ 3 · slugs PUBLISHED presentes · ningún DRAFT
2GET /api/pieces/merienda-en-el-banco200 · kicker/title/body/authorName · cover merienda.jpg
3POST /api/auth/login redaccion@margen.barrio / password123200 · accessToken · user.role=EDITOR
4GET /api/mesa/pieces con Bearer200 · incluye DRAFT lo-que-el-ampa-no-cuelga
5ng build o serve webWeb arranca o build OK

[COMPROBADO] Smoke = current + pieza + login JWT + mesa.

2. Casos funcionales

IDCasoEsperado
S1Slugs seed publicadoscurrent incluye merienda-en-el-banco, puerta-del-cole, vaso-de-agosto, silencio-y-patio
S2DRAFT no sale en currentlo-que-el-ampa-no-cuelga ausente del array público
S3Slug DRAFTGET /api/pieces/lo-que-el-ampa-no-cuelga 404
S4Slug inexistente404
S5AgendaGET /api/events length = 3 · orden startsAt asc
S6Agenda UI/agenda muestra 3 eventos y disclaimer; cero CTA Inscribirse
S7Ficha ACkicker, título, cuerpo, crédito visibles
S8Lookbook 16:10portada + cards con recorte 16:10 (no 1:1)
S9Mesa sin JWT401 / redirect login
S10POST pieza201 · status=DRAFT · slug kebab
S11PATCH PUBLISHED200 · la pieza aparece en current
S12PATCH DRAFT (retirar)200 · desaparece de current · slug público 404
S13Login malo401 · mensaje en form
S14Empty lookbook (Issue sin pieces PUBLISHED)UI-08
S15API caídaUI-08 + Reintentar conserva la vista
S16LoadingUI-09 skeletons antes del primer paint
S17Mobile 390Lookbook + ficha leíbles; CTA ≥44px; no hero 2-col
S18Fotos seed5 covers resuelven a assets
S19Password no viaja de vueltalogin response sin hash
S20Body POSTacepta title, kicker, body, cover, section
S21Success/mesa/ok/:slug copy “Publicar no es imprimir”
S22Público no lista mesaGET mesa sin token 401 (no 200 [])

3. Datos de prueba

UsoValor
EDITORredaccion@margen.barrio / password123
LECTORAElena Vargas · sin cuenta
Pieza felizmerienda-en-el-banco
Pieza DRAFTlo-que-el-ampa-no-cuelga
Evento felizMerienda de patio en Pradolongo
weekLabel17–23 ago

4. Regresión de diversidad / craft

CheckFalla si
Home es galeríaHay hero 2-col + 3 cards de marca (AP-12) o tabla de filas (CESTA) o feed (RONDA)
Shell es mastheadHay rail, dock flotante, sidebar CMS o command search como nav primaria
Copy honestoSuccess dice “ya está en el kiosco” o agenda dice “inscríbete”
PaletaSe cuelan musgo CESTA / cromo RONDA / chalky PIZARRA / hielo PRIMA
TipoNewsreader / Outfit / Spectral / Manrope / Zilla / Mulish / Lora / Karla
RutasAparecen /inscribir, /walks, /necesidades, /inbox, /donar
GroundPágina en pliego #F4F1EA en vez de papel #FFFFFF

5. Hipótesis (no se “prueban” en la demo)

H1, H2, H3 requieren uso real. El QA verifica que existen las superficies que permitirían medirlas (tap en card, disclaimer de agenda, ausencia de signup lectora, DRAFT 404).

6. Criterios de salida QA v1

  • Smoke §1 en verde.
  • S2, S3, S6, S8, S11, S17, S21, S22 en verde.
  • Cero blockers de copy deshonesto (imprimir / inscribir / like).
  • Sin .env en el repo.

7. Fuera de este plan

Playwright e2e completo, carga, fuzzing, auditoría de un CEIP o biblioteca reales.

14-dev-handoff.md

14 — Handoff desarrollo — MARGEN

1. Arranque

cd /Users/cristian/orca/margen-app

# apps independientes (npm --prefix o pnpm --filter)
# apps/api/.env
#   DATABASE_URL=  # Neon morning-truth-64427459
#   JWT_SECRET=
#   PORT=3017

# migrate / ensureSchema + seed
# api → http://localhost:3017
# web → http://localhost:4200

Demo: redaccion@margen.barrio / password123.

2. Paridad Paper

Debe verse en AngularArtboard
Tokens gallery + Cormorant/Public SansUI-00
Lookbook 16:10 + mastheadUI-01, UI-10
Ficha con kicker, cuerpo, créditoUI-02
Agenda 3 eventos + disclaimerUI-03
Login EDITORUI-04
Mesa DRAFT / PUBLISHEDUI-05
Alta de piezaUI-06
Success “no es imprimir”UI-07
Empty / error / loadingUI-08…09

No clonar CESTA (tabla + rail), RONDA (feed + dock), DERIVA (mapa split) ni PIZARRA (command search + inscripción).

Paper se construye en paralelo; los nombres de artboard son el inventario planificado (doc 00).

3. Contratos

TemaContrato
Login{ accessToken, user } camelCase (no access_token)
LookbookGET /api/issues/current → issue + pieces PUBLISHED
FichaGET /api/pieces/:slug · 404 si DRAFT
AgendaGET /api/events
MesaGET /api/mesa/pieces Bearer
AltaPOST /api/pieces { title, kicker, body, cover, section, issueId?, authorName? }
StatusPATCH /api/pieces/:id { status }
Status enumDRAFT | PUBLISHED
Section enumPATIO | COLE | BARRIO | LECTURA

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

4. Mapa de rutas web

PathGuard clientePágina
/noLookbook
/piezas/:slugnoFicha
/agendanoAgenda
/loginnoLogin
/mesasoft (redirect)Mesa
/mesa/nuevasoftAlta
/mesa/ok/:slugsoftSuccess

Soft guard: si no hay token, /login?next=. La API es la autoridad.

[COMPROBADO] Solo estas rutas. No implementar /inscribir, /inbox, /walks, /mesa/:id.

5. Assets

Copiar desde el case:

2026-08-17-margen/assets/hero.jpg
2026-08-17-margen/assets/merienda.jpg
2026-08-17-margen/assets/colegio.jpg
2026-08-17-margen/assets/piscina.jpg
2026-08-17-margen/assets/biblioteca.jpg
  → apps/web/public/assets/   (o src/assets/)

cover del seed = filename (hero.jpg, merienda.jpg, …).

Quitar leftover public/assets/needs/* (despensa CESTA) si sigue en el repo.

6. DoD implementación L2

CheckOK
API sirve :3017
Seed 1 EDITOR + 1 Issue + 4 PUBLISHED + 1 DRAFT + 3 events
Smoke GET current + GET pieza + login + GET mesa
JWT protege mesa / POST / PATCH
DRAFT 404 en público
Web lookbook + ficha + agenda + mesa + alta + success
Microcopy ×3 (imprimir / borrador / inscripción)
Tokens Tailwind = paleta brief
Recorte 16:10 en portadas
ng build o equivalente OK
README del repo app con credencial
Home es galería (no leftover walks / tabla / feed)

7. No hacer

ProhibidoMotivo
npm workspacesAP-06
Commit de .envSecreto
Prometer tiraje o inscripciónMicrocopy duro / AP-09
Estado SEATED / ENROLLED / CONTACTED / RECEIVEDVocabulario de otros días
Search bar o mapa como homeRompe H-GALLERY
Hero 2-col + 3 cardsAP-12
Tabla de necesidades como homeCESTA
Feed + dockRONDA
image_gen como captura de productoD-P0-09
Body POST con needSlug / tableSlug / walkIdLeftover

8. Contactos de diseño (artefactos)

ArtefactoPath
Briefux-projects/2026-08-17-margen/docs/00-day-brief.md
Paperhttps://app.paper.design/file/01M078GFW7QQF5RRA2XGKQ8BD9
Datosdocs/05-data-model.md
Flujosdocs/04-user-flows.md
IXdocs/16-interaction-specs.md
Builddocs/20-implementation.md

15-roadmap.md

15 — Roadmap — MARGEN

Este documento no es un cajón de trabajo L2 a medias.
El vertical slice L2 del brief está especificado como done-scope (docs 01, 18, 19).
Aquí solo viven ideas de L+1 / L3 y pulido posterior.

1. Hecho en L2 (esta ejecución documental)

EntregaEvidencia
Definición producto + ternadocs 00-brief, 01
Personas Elena / Nuria / Raúl, JTBD, journeydocs 02
IA gallery + mastheaddocs 03
Flujos F-STORY + mesa EDITORdocs 04
Modelo issues / pieces / events / users + seeddocs 05
Stack Angular/Nest/Neon/JWT :3017docs 06, 20
Dirección gallery/newsstand + DSdocs 07, 08
Copy Publicar ≠ imprimir · Borrador ≠ publicado · Agenda ≠ inscripcióndocs 09
Paper ref 12 UX + 11 UIdocs 00-paper-reference
Suite 00–20 + README + executivecase folder

2. Implementación L2 (misma complejidad, código)

Contrato en docs 14 y 20. No es deuda silenciosa del case documental: es el build del repo margen-app. El alcance L2 ya está cerrado en spec; el código alinea leftover (walks / requests) al contrato.

Eso no se reabre aquí como “próximo trimestre de producto”.

3. L+1 (misma familia, subida de pulido o archivo)

ÍtemNotas
Archivo de números /numeros/:weekHome sigue siendo el current; no search-first
Preview de DRAFT con tokenNo 200 público
authorUserId + segundo bylineSigue siendo 1–2 personas
Rate limit loginAnti stuffing
Playwright S1–S22CI
Copiar enlace de piezaCould lectora
Despublicar con confirmPATCH DRAFT
API URL por environmentDeploy
prefers-reduced-motion verificadoa11y
CMS mínimo de EventSigue sin inscripción

Estas son subidas de pulido o archivo, no parches del L2 documental.

[DECISIÓN] No dejar backlog del vertical slice como “mañana”. Lo de arriba es L+1.

4. L3 (requiere brief nuevo de diversidad)

  • Multi-distrito / varias cabeceras
  • Cuenta LECTORA y bookmarks
  • Newsletter transaccional “ha salido el número”
  • Workflow REVIEW / SCHEDULED / KILLED
  • Comentarios o cartas al director
  • Impresión / PDF de kiosco / punto de venta
  • Paywall
  • Search como home (rompería terna)

5. Explícitamente fuera (no backlog disfrazado)

ÍtemPor qué
Inscripción / cupo / WAITLISTH2 · ≠ PIZARRA
Tabla de necesidades / compromiso≠ CESTA
Feed de historias + dock≠ RONDA
Mapa de meriendas≠ DERIVA
Likes / rankingS4
App nativaFuera de stack daily
Hero 2-col + 3 cardsAP-12

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

  1. Contratos 05–06 + seed 05 + smoke 13 (alinear leftover)
  2. Web paridad UI-00…10
  3. Preview token + archivo de números (L+1)
  4. Rate limit si hay tráfico
  5. Evaluar brief L3 (no parche silencioso)

16-interaction-specs.md

16 — Especificación de interacción — MARGEN

1. Convenciones

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

2. Masthead (S-TOP)

GestoResultado
Tap Número/ ; aria-current se mueve
Tap Agenda/agenda
Tap Mesa sin sesión/login?next=/mesa
Tap Mesa con sesión/mesa
Tap Salirlimpia token → /login
Scroll de la galeríaMasthead puede ser sticky (Should); no se esconde
TecladoTab: wordmark → links → contenido

Estado activo: label tinta + filete 2px cadmio bajo el ítem.
Estado default: grafito.

Desktop: links a la derecha.
390: wordmark + Número + Agenda; Mesa entra en la misma fila si cabe, si no bajo la rule.


3. Lookbook home

GestoResultado
Tap portada del númeroNo lightbox. Scroll al grid o abre la pieza lead (merienda-en-el-banco). [DECISIÓN] abre la lead
Tap card/piezas/:slug (card completa clicable, un solo enlace)
Tap “Agenda de la semana”/agenda
Pull-to-refreshNo en v1; Reintentar solo en error
Primera cargaSkeleton portada 16:10 + 3 cards; no spinner centrado de marca
0 publicadosEmpty UI-08
ErrorBanner bajo masthead + Reintentar (refetch)
Hover desktopRule 1px grafito; no elevación de card

AC: la portada 16:10 (foto + título del número) está en el viewport inicial a 390 y a 1280 (sin hero de 60vh de marca).

Orden visual = seed / createdAt ASC. No “destacados” por likes.

390 (UI-10): portada full + pila de cards. Lead de 2 líneas. Título Cormorant 32.


4. Ficha de crónica

GestoResultado
ScrollLectura normal; sin scroll-jacking
Tap ← El número/
Tap Agenda (masthead o pie)/agenda
FotoNo lightbox v1
Selección de textoPermitida (compartir por WhatsApp es backstage)

Sin doble tap like. Sin barra de progreso de lectura como Must (Could L+1, off si reduced-motion).


5. Agenda

GestoResultado
Tap eventoNada que parezca form. Could: expande nota. [DECISIÓN v1] no hay expansión; el bloque ya está completo
HoverSin CTA que aparezca (“Apuntarme”)
EmptyTitular + 1 línea
ErrorBanner + Reintentar

Si un tester busca un botón de reserva y no lo encuentra, H2 está bien implementada.


6. Login

GestoResultado
SubmitPOST login; pending en botón
200Guarda token + user; navega next sanitizado o /mesa
401Texto bajo el form; password no se limpia
EnterSubmit

next permitido: paths que empiezan por / y no // ni http. Allowlist sugerida: /mesa, /mesa/nueva.


7. Mesa

GestoResultado
Sin tokenRedirect login
Tap Nueva pieza/mesa/nueva
Tap Publicar en fila DRAFTPATCH PUBLISHED; badge cambia
Tap títuloCould: no hay /mesa/:id. [DECISIÓN] el título no navega; Publicar y “ver” (link a ficha si PUBLISHED) sí
EmptyTitular + CTA Nueva
Error 401 mid-sessionRedirect login
Error redBanner + Reintentar

No swipe-to-archive. No kanban.

Optimistic UI en Publicar: badge pasa a Publicado; si PATCH falla, rollback + toast error.

Publicar no anima una rotativa ni un “+1 en kiosco”.


8. Alta de pieza

CampoInteracción
titletext, autocomplete off
kickertext
sectionselect PATIO / COLE / BARRIO / LECTURA
coverselect de filenames seed (preview 16:10)
bodytextarea 8+ filas
authorNamedefault Nuria Ceballos, editable
GestoResultado
Guardar borradorPOST DRAFT; redirect /mesa o /mesa/ok/:slug con copy de borrador
PublicarPOST + PATCH PUBLISHED → /mesa/ok/:slug
Submit inválidoFoco al primer campo error; no POST
Error redBotón Reintentar; no limpia campos
Doble tapIgnorado mientras pending

Submit deshabilitado si title < 4, body < 40 o section vacía.

[DECISIÓN] Dos botones visibles. Primario = Publicar. Secundario = Guardar borrador. El primario no se llama “Imprimir”.


9. Success

GestoResultado
CTA primarioVer la pieza pública /piezas/:slug
CTA secundarioVolver a la mesa /mesa
CopyVisible “Publicar no es imprimir”

Sin confetti. Sin “¡ya está en el kiosco!”.


10. Motion

SuperficieSpec
Cards lookbookFade 160ms, stagger ≤30ms (off si reduced-motion)
Cambio de badgeCrossfade 120ms
MastheadSin hide-on-scroll v1
SkeletonsEstáticos o pulso 1.2s opacity 0.6–1; off si reduced-motion

Prohibido: scroll-jacking, page transitions de 400ms, parallax en portada, like animation.


11. Criterios de aceptación de interacción

  1. Una LECTORA en 390px llega de lookbook a ficha en 1 tap, y a agenda en 1 tap más (masthead).
  2. Un EDITOR en 390px publica un DRAFT en ≤ 3 taps desde mesa (acción en fila).
  3. Ningún submit permite doble POST.
  4. El masthead no cubre el H1 de la ficha (spacer si sticky).
  5. Reduced-motion elimina stagger.
  6. La home no es hero 2-col (AP-12).
  7. En 390 el recorte 16:10 de la primera card es visible sin scroll horizontal.
  8. /agenda no presenta ningún control de inscripción.

17-prototype-map.md

17 — Mapa de prototipo — MARGEN

Paper no es clicable vía MCP. El prototipo vivo es la app Angular.
Los artboards de Paper se construyen en paralelo; esta tabla es el contrato de paridad.

RutaPaperRol
/UI-01, UI-08, UI-09, UI-10LECTORA
/piezas/:slugUI-02, UI-10LECTORA
/agendaUI-03LECTORA / AMPA
/loginUI-04EDITOR
/mesaUI-05EDITOR
/mesa/nuevaUI-06EDITOR
/mesa/ok/:slugUI-07EDITOR

Proceso: UX-00…UX-11. Tokens: UI-00.

Recorrido demo (guión)

  1. Abrir / — lookbook El patio no cierra en agosto, portada hero.jpg, ≥3 cards 16:10.
  2. Tocar La merienda que no cabe en el grupo — ficha Patio, crédito Nuria.
  3. Masthead Agenda — 3 eventos; leer “no es una inscripción”.
  4. Comprobar que no hay botón Reservar.
  5. /loginredaccion@margen.barrio / password123.
  6. /mesa — ver DRAFT Lo que el AMPA no va a colgar en Stories.
  7. Nueva pieza o Publicar el DRAFT → /mesa/ok/:slug — “Publicar no es imprimir”.
  8. Volver a / en otra sesión: el DRAFT no está; lo publicado sí.

Estados en el mismo prototipo

EstadoCómo provocarlo
Empty lookbookAPI 200 current con pieces: []
Empty agendaevents []
Empty mesalista vacía autenticada
ErrorAPI caída / 5xx
Loadingthrottle de red
404 DRAFT/piezas/lo-que-el-ampa-no-cuelga sin publicar
Mobile lector390 × 844

Fuera del prototipo clicable

  • Paper artboards son estáticos.
  • WhatsApp del AMPA / grupo del cole (backstage).
  • Impresión / kiosco físico.
  • Inscripción a eventos (no existe).
  • Comentarios.
  • Archivo de números anteriores.

18-completeness-audit.md

18 — Auditoría de completitud — MARGEN (2026-08-17)

1. Alcance auditado

Vertical slice L2: lookbook del número semanal + ficha de crónica + agenda familiar + mesa EDITOR JWT, con docs, referencia Paper, contratos Angular + Nest + Neon.

Este encargo cubre la suite documental. Paper hi-fi y el repo margen-app pueden existir en paralelo; la auditoría marca lo que esta suite cierra. El day brief no se ha sobrescrito.

2. Checklist CRON / ALS-2

RequisitoEstadoEvidencia
Diversidad sector/tipo/nivelOKEditorial local L2; no tabla; no feed; no mapa; no search; no inscripción
Terna S/H/F 0 códigos = N−1 · ≥2 vs N−2OKS-TOP · H-GALLERY · F-STORY vs CESTA S-RAIL · H-TABLE · F-LEAD
Day brief + anti-patronesOKdocs/00-day-brief.md (no sobrescrito)
Paper ≥12 UX + ≥10 UIOKUX-count 12 · UI-count 11 · file 01M078GFW7QQF5RRA2XGKQ8BD9
Docs 00–20OKsuite en docs/ + executive + README
JWT EDITOROKRole EDITOR · D-P1-05
API + seed + NeonOKcontratos morning-truth-64427459, port 3017
Web tokensOKCormorant + Public Sans · paleta gallery
Gallery-first (no AP-12)OKUI-01 / docs 03, 07, 08
Hipótesis no fake fieldOKetiquetas en doc 02
Copy publicar ≠ imprimir · agenda ≠ inscripción · borrador ≠ publicadoOKdocs 01, 09, 16
Ground G-GALLERYOK#FFFFFF · no G-MOSS / G-CHROME / G-WATER / G-MUNICIPAL / G-ICE

3. Cobertura funcional

Feature briefSpecUI PaperAPIDocs
Home lookbook + ≥3 portadas 16:10UI-01, UI-10GET current03, 04, 16
Ficha kicker / título / cuerpo / créditoUI-02GET :slug05, 09
Agenda 3 eventosUI-03GET events04, 05
Login EDITORUI-04POST login04, 06
Mesa DRAFT → PUBLISHEDUI-05GET mesa + PATCH04, 05
Alta + successUI-06, UI-07POST pieces04, 09
EmptyUI-08200 []16
ErrorUI-085xx/red16
LoadingUI-09pending16
Design systemUI-0008
Seed 1 número + 4 piezas + 3 eventosseed05
MastheadUI-01, UI-1003, 08
Mobile lectorUI-1010, 16

4. Cobertura Paper (literales)

IDNombreEn 00-paper-reference
UX-00Cover
UX-01Stakeholders
UX-02Personas
UX-03JTBD
UX-04Stories
UX-05Journey
UX-06Blueprint
UX-07Site map
UX-08Flujos
UX-09Datos+permisos
UX-10Métricas
UX-11Research
UI-00Tokens
UI-01Lookbook
UI-02Crónica
UI-03Agenda
UI-04Login
UI-05Mesa
UI-06Alta pieza
UI-07Success
UI-08Empty / Error
UI-09Loading
UI-10Mobile lector

[COMPROBADO] UX-count: 12 y UI-count: 11 literales para el gate check-paper-reference.mjs. Paper hi-fi en construcción paralela; inventario planificado escrito.

5. Rúbrica de calidad (auto SCORE orientativo · docs)

EjeScore 1–5Comentario
Diversidad5Gallery+masthead vs tabla CESTA, feed RONDA y mapa DERIVA; L2 no L1
Craft visual (spec)4–5Gallery/newsstand + Cormorant/Public Sans + fotos de barrio documentadas
Densidad UX docs5Suite L2: tablas, AC, etiquetas S/H/D
Completitud código L2App fuera o en paralelo; leftover scaffold anotado
Authz5Contrato: guard en mesa/POST/PATCH; DRAFT 404
Verdad investigación5Sin entrevistas ni stats de campo falsas

6. Huecos aceptados (no regresiones de cierre documental)

HuecoClasificación
Paywall / comentarios / inscripción / mapa / search-homeFuera L2
e2e automatizadoL+1
Preview token de DRAFTL+1
Archivo de númerosL+1
Leftover walks / requests en repoBuild; contrato de esta suite gana
Paper/app no necesariamente tocados aquíEncargo = documentación

7. Veredicto

COMPLETO para entrega documental del caso 2026-08-17.
La suite define producto L2 usable (tablas, AC, riesgos, contratos) sin presentar investigación de campo como hecho.
Cualquier ampliación inscripción / paywall / feed / mapa / search-first requiere nuevo brief de diversidad, no parche silencioso.

19-backlog-completo.md

19 — Backlog completo — MARGEN

Inventario de ítems. Los del alcance L2 documental del día están Done.
El resto es opcional / siguiente nivel, no deuda oculta del cierre.

1. Done — L2 case documental (2026-08-17)

IDÍtemCapa
D01Definición producto MARGEN + esloganDocs
D02Day brief diversidad editorial L2Docs (preexistente, no pisado)
D03Terna R-CL · S-TOP · H-GALLERY · F-STORYDocs
D04Personas Elena Vargas / Nuria Ceballos / Raúl MéndezDocs + Paper ref
D05JTBD + stories MustDocs
D06IA gallery-first + mastheadDocs
D07Flujos F1–F9 + ACDocs
D08Modelo users / issues / pieces / eventsDocs
D09Contratos API :3017Docs
D10Auth JWT EDITORDocs
D11Estados DRAFT / PUBLISHED + 404 de borradorDocs
D12Agenda de solo lectura (3 eventos)Docs
D13Microcopy ×3 (imprimir / borrador / inscripción)Docs
D14North star lectura de número (pieza + agenda)Docs
D15Tokens gallery + Cormorant / Public SansDocs
D16Paper UX-00…11 + UI-00…10Docs
D17Suite docs 00–20 + README + executiveDocs
D18Seed 1 número + 4 piezas + 1 DRAFT + 3 eventosDocs
D19Assets listados (5 fotos)README
D20QA smoke + S1–S22Docs
D21Neon morning-truth-64427459Docs
D22Recorte 16:10 de portadas especificadoDocs
D23Ground G-GALLERY #FFFFFFDocs
D24Rutas reales solo las 7 del encargoDocs

Los must-have del brief (lookbook, ficha, agenda, login+mesa, alta+success, empty/loading/error/mobile, ≥12 UX + ≥10 UI) están dentro de D01–D24, no como leftover.

2. Backlog L2 implementación (repo margen-app)

Alineación de código al contrato ya cerrado. No es alcance documental pendiente.

IDÍtemPrioridadNotas
I01Alinear apps/api + apps/web al contrato MARGENP0quitar leftover walks/requests/needs
I02Schema issues / pieces / events / usersP0
I03Seed Nuria + número + 5 piezas + 3 eventsP0
I04GET current / pieces/:slug / eventsP0DRAFT → 404
I05POST pieces + PATCH :id { status }P0
I06POST login JWTP0redaccion@margen.barrio
I07GET mesa/piecesP0
I08Lookbook + masthead AngularP016:10
I09Ficha / agenda / login / mesa / alta / okP0
I10Tokens Tailwind + fotosP0
I11Smoke curl + buildP0D-P1-06
I12Puerto API 3017P0

3. Backlog L+1 (polish / archivo)

IDÍtemPrioridadNotas
B01canActivate guards AngularP1UX auth
B02Archivo /numeros/:weekP2home sigue current
B03Preview token DRAFTP1no 200 público
B04Rate limit loginP1anti stuffing
B05Playwright smokeP1CI
B06Skeleton UI-09 en códigoP2
B07Copiar enlace de piezaP3
B08Confirm al revertir a DRAFTP2
B09API URL por environmentP1deploy
B10Página 404 amigableP3
B11Sessions invalidablesP2
B12CMS Event (sigue sin inscripción)P2

4. Backlog L3 (requiere brief nuevo)

IDÍtemDependencia
C01Multi-cabecera / varios distritosvenues + membership
C02Cuenta LECTORA + bookmarksauthz
C03Newsletter “ha salido el número”provider
C04Workflow REVIEW / SCHEDULEDestados
C05Comentarios / cartasS4 se rompe · brief nuevo
C06Impresión / PDF kioscoPublicar ≠ imprimir se renegocia
C07PaywallS2 se rompe
C08Search-first homerompe terna

5. Backlog explícitamente fuera

IDÍtem
E01Inscripción / cupo / WAITLIST
E02Tabla de necesidades / compromiso de caja
E03Feed de historias + dock
E04Mapa de meriendas / paseos
E05Likes / ranking
E06App nativa
E07Hero 2-col + 3 cards de marca

6. Explicitamente no-backlog

IdeaRazón
Hero 2-col + 3 cardsAP-12 / rompe H-GALLERY
Sidebar CMSS-SIDE
Dock flotanteS-DOCK de RONDA
Rail de iconosS-RAIL de CESTA
Command search municipalPIZARRA
Split mapaDERIVA
Wizard de publicación 4 pasosF-ONB
Form “apúntame a la merienda”H2

7. Orden de ataque recomendado (continuidad de código)

  1. I01–I12 (vertical slice runnable, sin leftover)
  2. B01 + B05 + B09
  3. B03 + B08
  4. B02 si hay segundo número
  5. Evaluar brief L3 — no parche silencioso

8. Trazabilidad

OrigenÍtems
Day brief must-haveD01–D24, I01–I12
Doc 15 L+1B01–B12
Doc 15 L3 / fueraC01–C08, E01–E07

20-implementation.md

20 — Implementación — MARGEN

1. Resumen ejecutivo técnico

CampoValor
App path/Users/cristian/orca/margen-app
APINestJS · puerto 3017 · prefijo /api
WebAngular standalone · puerto 4200
Packageapps independientes (npm --prefix o pnpm --filter)
DBNeon PostgreSQL · project morning-truth-64427459
Tablasusers, issues, pieces, events (+ sessions Should)
AuthJWT Bearer · role EDITOR
DominioUser, Issue, Piece, Event
Fecha2026-08-17
GitHubhttps://github.com/Criscode2022/margen-app

Este documento es la especificación de build alineada al case. No sustituye al código: si el repo diverge, gana el contrato de docs 05 + este archivo tras actualizar ambos.

[COMPROBADO] Path, puerto, Neon, Paper y GitHub salen del encargo.
[COMPROBADO] El repo existe; contiene leftover de otros productos (walks, requests, assets de despensa). El contrato de esta suite es MARGEN.

2. Cómo arrancar

cd /Users/cristian/orca/margen-app
# instalar dependencias por app (no npm workspaces)

# apps/api/.env
#   DATABASE_URL=   # Neon morning-truth-64427459
#   JWT_SECRET=
#   PORT=3017

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

Credenciales

RolEmailPassword
EDITORredaccion@margen.barriopassword123

3. Schema

Al boot o vía migrate:

  1. CREATE TABLE / migrate de users, issues, pieces, events (doc 05).
  2. Índices: issues(status, published_at DESC), pieces(slug), pieces(issue_id, status), pieces(updated_at DESC), events(issue_id, starts_at), users(email).
  3. Seed idempotente:
    • upsert EDITOR redaccion@margen.barrio (bcrypt de password123)
    • upsert Issue por week_label
    • upsert pieces por slug
    • upsert events por (issue_id, title)

No borrar datos de usuario en cada boot si ya existen filas distintas al seed.

Tablas (recordatorio)

TablaContenido
usersEDITOR Nuria
issues1 número seed PUBLISHED
pieces4 PUBLISHED + 1 DRAFT
events3 citas de agenda
sessionsShould: sid + token_hash + expires_at

4. Módulos API a implementar

Auth

  • POST /api/auth/login
  • Valida email/password; compara bcrypt; emite JWT con sub, email, role.
  • Guard JWT + role === EDITOR protege mesa / escritura.

Issues / pieces / events

MétodoRutaAuthNotas
GET/api/issues/currentNoIssue PUBLISHED más reciente + pieces PUBLISHED
GET/api/pieces/:slugNo404 si no existe o DRAFT
GET/api/eventsNoevents del current, startsAt asc
GET/api/mesa/piecesJWTtodas; updatedAt desc
POST/api/piecesJWTcrea DRAFT; slug kebab
PATCH/api/pieces/:idJWT{ status } y/o campos

Slug

kebab(title)  +  opcional "-2" si unique falla

Reintentar sufijo (máx. 5). No UUID en URL de lectura.

[DECISIÓN] Timezone Europe/Madrid para weekLabel y startsAt de UI. JSON transporta ISO UTC.

Filtro público

current.pieces = pieces WHERE issue_id = current.id AND status = 'PUBLISHED'
GET /pieces/:slug = 404 unless status = 'PUBLISHED'

Publicar no toca events ni genera PDF.

5. Frontend a implementar

PáginaRutaResponsabilidad
HomePage/GET current, lookbook 16:10, empty/loading/error, masthead
PiecePage/piezas/:slugGET slug, ficha, 404 DRAFT
AgendaPage/agendaGET events + disclaimer
LoginPage/loginform → login → mesa
DeskPage/mesalist + PATCH en fila + empty/error + logout
NewPiecePage/mesa/nuevaform create + Guardar / Publicar
OkPage/mesa/ok/:slugconfirmación + “no es imprimir”

Shell: MastheadComponent persistente.
ApiService centraliza base URL http://localhost:3017/api, token storage (margen_token, margen_user), métodos tipados (Issue, Piece, Event, User).

6. Decisiones de implementación

DecisiónRazón
Puerto API 3017Evitar colisión con CESTA 3016
Tablas issues / pieces / eventsDominio editorial, no leftover walks / requests
Soft auth en páginas de mesaSimple; API es autoridad
Sin FK User–PieceByline texto (authorName)
Slug kebabURL de lectura humana
Templates standaloneVelocidad daily
Crear siempre DRAFTBorrador ≠ publicado
Home no usa hero 2-colAP-12 / H-GALLERY
PUBLISHED no ENROLLED / RECEIVEDDominio de crónica, no municipal ni despensa
JSON camelCaseConvenio web serie daily
PATCH :id con { status }Contrato del encargo
Success /mesa/ok/:slugBoard UI-07
Cover allowlistEvitar URL arbitraria

7. Variables de entorno

VariableServicioDescripción
DATABASE_URLAPINeon morning-truth-64427459
JWT_SECRETAPIFirma tokens
PORTAPIopcional, 3017
JWT_EXPIRESAPIopcional, default 12h

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

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

  1. Schema OK (tablas existen).
  2. GET /api/issues/current incluye 4 slugs PUBLISHED y cero DRAFT.
  3. GET /api/pieces/lo-que-el-ampa-no-cuelga 404.
  4. GET /api/events length 3.
  5. POST /api/auth/login 200 + accessToken.
  6. GET /api/mesa/pieces Bearer incluye el DRAFT.
  7. GET /api/mesa/pieces sin token 401.
  8. PATCH /api/pieces/:id { status: "PUBLISHED" } 200 y la pieza aparece en current.
  9. Web: lookbook dominante, masthead, disclaimer agenda, fotos 16:10.

9. Estructura de ficheros clave (objetivo)

margen-app/
├── package.json
├── apps/api/
│   ├── src/
│   │   ├── main.ts
│   │   ├── app.module.ts
│   │   ├── auth/
│   │   ├── issues/
│   │   ├── pieces/
│   │   └── events/
│   └── .env.example
├── apps/web/
│   ├── tailwind.config.js
│   └── src/app/
│       ├── app.routes.ts
│       ├── core/api.service.ts
│       ├── shell/masthead.component.ts
│       └── pages/
│           ├── home/          # lookbook
│           ├── piece/
│           ├── agenda/
│           ├── login/
│           ├── desk/
│           ├── new-piece/
│           └── ok/
└── README.md

Nombres de fichero orientativos; el contrato es de rutas y tablas, no de filenames exactos.

10. Seed — checklist de implementación

#Check
1User Nuria Ceballos / redaccion@margen.barrio / password bcrypt de password123
2Issue 17–23 ago · El patio no cierra en agosto · hero.jpg · PUBLISHED
34 pieces PUBLISHED con slugs de doc 05 y covers alineados a assets
41 piece DRAFT lo-que-el-ampa-no-cuelga
53 events (Pradolongo, AMPA, cuento) con starts_at Europe/Madrid
6Secciones PATIO / COLE / BARRIO / LECTURA
7Idempotencia: upsert por email / week_label / slug / (issue, title evento)

11. Alineación case ↔ app

DocEvidencia esperada en código
05 data modelcolumnas y enums
03–04 IA/flowsroutes + controllers
08 DStailwind colors + fontFamily Cormorant/Public Sans
09 contentstrings en templates (microcopy ×3)
00 paperURLs en README case
11 securityGuard en mesa/POST/PATCH; DRAFT 404

12. Notas de cierre técnico

  • El case documental L2 está especificado (docs + Paper ref + contratos).
  • Must-have de producto del brief están escritos con AC.
  • Mejoras (preview token, archivo, e2e, rate limit) viven en backlog L+1, no como deuda silenciosa.
  • Si el repo aún muestra walks / requests / fotos de aceite, no está alineado: I01 es el primer ítem de build.