ADR-082 — Rutas de app Subscriber B2C (sin slug en URL)

Architecture decision record — status: Accepted.

Source: docs/adr/ADR-082-subscriber-app-routes-b2c.md

ADR-082: Rutas de app Subscriber B2C (sin slug en URL)

Estado

Accepted — 2026-09-09

Contexto

La fábrica FoodHub modelaba muchos tenants en una misma instalación: el usuario elegía “en qué restaurante entrar” y la URL llevaba el slug (/t/{slug}/login → hoy /s/{slug}/login tras FEAT-004).

IVPrior es B2C (DOC-002): V1 = un humano = un Subscriber. El email identifica la cuenta; el JWT ya incluye subscriberId. Exigir /s/demo/login confunde al trader (“¿qué es demo?”) y replica un patrón B2B que no aplica.

FEAT-004 fijó /s/{subscriberSlug}/… como paso intermedio del rename tenant→subscriber. Este ADR enmienda esa decisión de rutas de producto hacia URLs planas orientadas al usuario final.

El subscriber.slug sigue existiendo en base de datos (unicidad, emails de soporte, integraciones futuras) pero deja de ser segmento de ruta en la app autenticada y en el login.

Decisión

Superficie pública y auth

RutaUso
/Marketing (S-100)
/signupAlta self-serve (S-003)
/loginSign-in Subscriber global (S-001) — email + password
/forgot-password, /reset-password, /verify-emailFlujos de identidad (sin slug)

Prohibido en copy nueva: “ingresa el slug de tu workspace”, “elige tu cuenta”, URLs del tipo /s/{slug}/login.

App autenticada del Subscriber

Prefijo canónico: /app/*

Ejemplos (paridad con sitemap actual):

Hoy (legacy)Target
/s/{slug}/dashboard/app/dashboard
/s/{slug}/scanner/app/scanner
/s/{slug}/scanner/watchlist/app/scanner/watchlist
/s/{slug}/billing/app/billing
/s/{slug}/settings/app/settings

El middleware/layout resuelve el Subscriber desde el JWT (subscriberId), no desde un param de ruta.

Platform (sin cambio)

/platform/login y /platform/* permanecen para PlatformUser (universo JWT distinto, ADR-023).

Corte y compatibilidad

Alineado a FEAT-004 (sin aliases permanentes):

  1. Tras el slice de migración, rutas /s/{slug}/… y /t/{slug}/… responden 404 (no redirect 301/308 indefinido).
  2. Opcional una release con redirect temporal documentado en el change OpenSpec (solo login y dashboard) si hace falta para demos internas; se elimina en el mismo epic antes de producción.
  3. Emails y deep links se actualizan a /login y /app/… en el mismo PR que el corte.

API

  • Los endpoints REST del Subscriber ya usan subscriberId del token; no requieren slug en path.
  • Endpoints públicos que hoy usan /public/subscribers/{slug} para branding se reevalúan: en B2C V1 el branding es global de plataforma o por sesión, no por slug en URL.

Alternativas

OpciónNota
Mantener /s/{slug}Rechazada — modelo mental tenant, fricción en signup/login
/login + /app/*Elegida — estándar B2C SaaS
Subdominio {slug}.ivprior.comRechazada V1 — complejidad DNS/SSL sin beneficio B2C
Slug solo post-login en settingsAceptada — campo interno / URL de perfil opcional, no gate de auth

Consecuencias

  • Epic FEAT-006 (docs/product/features/FEAT-006-subscriber-flat-routes/brief.md): slices OpenSpec web + emails + e2e.
  • Actualizar docs/ux/sitemap.md, pantallas S-001, tests Playwright, SubscriberShell nav links.
  • subscriber.slug se genera en signup (unicidad) pero no se muestra en la barra de direcciones.
  • FEAT-004 brief: la fila “App Subscriber /s/{slug}” queda supersedida por este ADR para rutas de producto; el rename tenant→subscriber en código/API sigue vigente.
  • ADR-081 (GTM): zona M1 incluirá /login global cuando exista la ruta.

Referencias

  • DOC-002 §8 — leftover de fábrica
  • FEAT-004 — remap vocabulario (parcialmente enmendado en rutas)
  • FEAT-006 — brief de implementación