# US-ADM-002: Cambiar de Constructora (Multi-tenancy) **ID:** US-ADM-002 **MΓ³dulo:** MAI-013 **Relacionado con:** RF-ADM-001, ET-ADM-001 **Prioridad:** Alta **Story Points:** 5 --- ## πŸ“– Historia de Usuario **Como** usuario que pertenece a mΓΊltiples constructoras **Quiero** poder cambiar entre ellas fΓ‘cilmente desde la interfaz **Para** gestionar mis tareas en diferentes empresas sin tener que cerrar sesiΓ³n y volver a iniciar --- ## βœ… Criterios de AceptaciΓ³n ### 1. Selector de Constructora Visible ```gherkin Given que estoy autenticado y pertenezco a 2 o mΓ‘s constructoras When accedo a cualquier pΓ‘gina del sistema Then debo ver en el header un selector con: - Logo de la constructora actual - Nombre de la constructora actual - Indicador visual de que puedo cambiar (dropdown icon) ``` ### 2. Cambio de Constructora ```gherkin Given que tengo acceso a 3 constructoras: "Constructora A", "Constructora B", "Constructora C" And estoy actualmente en "Constructora A" When hago clic en el selector de constructora Then debo ver un dropdown con: - βœ“ Constructora A (actual, con checkmark) - Constructora B - Constructora C - Mi rol en cada una (debajo del nombre) When selecciono "Constructora B" Then el sistema debe: - Cambiar el contexto global a "Constructora B" - Recargar los datos segΓΊn el nuevo contexto - Actualizar el selector mostrando "Constructora B" como actual - Mantener la misma pΓ‘gina si tengo acceso con ese rol - Redirigir al dashboard si no tengo acceso a la pΓ‘gina actual - Registrar el cambio en audit log ``` ### 3. Persistencia de SelecciΓ³n ```gherkin Given que cambiΓ© a "Constructora B" When cierro el navegador And vuelvo a abrir la aplicaciΓ³n Then el sistema debe recordar mi ΓΊltima selecciΓ³n And abrir directamente en "Constructora B" ``` ### 4. Diferentes Roles por Constructora ```gherkin Given que tengo estos accesos: - Constructora A: rol "director" - Constructora B: rol "engineer" - Constructora C: rol "resident" When estoy en Constructora A Then debo ver menΓΊs y acciones de "director" (todos los permisos) When cambio a Constructora B Then debo ver menΓΊs y acciones de "engineer" (limitados) And no debo ver opciones administrativas ``` ### 5. Usuario con Una Sola Constructora ```gherkin Given que solo pertenezco a 1 constructora When accedo al sistema Then NO debo ver el selector de constructora And el sistema debe cargar automΓ‘ticamente esa constructora ``` ### 6. Datos Aislados por Constructora ```gherkin Given que estoy en "Constructora A" When veo la lista de proyectos Then solo debo ver proyectos de "Constructora A" When cambio a "Constructora B" Then solo debo ver proyectos de "Constructora B" And no debo poder acceder a datos de otras constructoras ``` --- ## 🎨 Mockup / Wireframe ### Header con Selector de Constructora ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ [≑] 🏒 Constructora A [β–Ό] Proyectos Presupuestos Obra β”‚ β”‚ πŸ‘€ Juan P. β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` ### Dropdown Expandido ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ [≑] 🏒 Constructora A [β–²] Proyectos Presupuestos Obra β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ βœ“ 🏒 Constructora A β”‚ β”‚ β”‚ β”‚ Director General β”‚ β”‚ β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ β”‚ β”‚ 🏒 Constructora B β”‚ β”‚ β”‚ β”‚ Ingeniero β”‚ β”‚ β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ β”‚ β”‚ 🏒 Constructora C β”‚ β”‚ β”‚ β”‚ Residente de Obra β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ πŸ‘€ Juan P. β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` ### TransiciΓ³n al Cambiar ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ [⏳ Loading spinner] β”‚ β”‚ β”‚ β”‚ Cambiando a Constructora B... β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` ### Header DespuΓ©s del Cambio ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ [≑] 🏒 Constructora B [β–Ό] Proyectos Presupuestos β”‚ β”‚ [Obra NO visible - sin permiso] β”‚ β”‚ πŸ‘€ Juan P. β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` --- ## πŸ§ͺ Casos de Prueba ### CP-001: Cambio Exitoso Entre Constructoras **Precondiciones:** - Usuario pertenece a "Constructora A" (director) y "Constructora B" (engineer) - Actualmente en "Constructora A" **Pasos:** 1. Clic en selector de constructora en header 2. Seleccionar "Constructora B" del dropdown **Resultado Esperado:** - βœ… Loader muestra "Cambiando a Constructora B..." - βœ… URL actualiza parΓ‘metro: `?constructora=uuid-b` - βœ… Header muestra "Constructora B" - βœ… Datos recargan para contexto B - βœ… MenΓΊs reflejan permisos de "engineer" - βœ… Audit log registra: "switched_constructora" ### CP-002: Persistencia de SelecciΓ³n **Precondiciones:** - Usuario cambiΓ³ a "Constructora B" **Pasos:** 1. Cerrar navegador completamente 2. Abrir nueva ventana 3. Navegar a la aplicaciΓ³n **Resultado Esperado:** - βœ… Abre directamente en "Constructora B" - βœ… No muestra selector de "Constructora A" ### CP-003: RedirecciΓ³n por Falta de Permisos **Precondiciones:** - Usuario en pΓ‘gina "/admin/usuarios" (requiere rol director) - En "Constructora A" con rol "director" **Pasos:** 1. Cambiar a "Constructora B" donde tiene rol "engineer" **Resultado Esperado:** - βœ… Redirecciona automΓ‘ticamente a "/dashboard" - βœ… Muestra toast: "No tienes acceso a esta secciΓ³n con tu rol actual" ### CP-004: Aislamiento de Datos **Precondiciones:** - Constructora A tiene 5 proyectos - Constructora B tiene 3 proyectos **Pasos:** 1. En Constructora A, navegar a "/proyectos" 2. Verificar que se muestran 5 proyectos 3. Cambiar a Constructora B 4. Verificar proyectos mostrados **Resultado Esperado:** - βœ… En Constructora A: muestra 5 proyectos - βœ… En Constructora B: muestra 3 proyectos - βœ… NingΓΊn proyecto se filtra entre constructoras ### CP-005: Usuario con Una Sola Constructora **Precondiciones:** - Usuario solo pertenece a "Constructora A" **Pasos:** 1. Iniciar sesiΓ³n **Resultado Esperado:** - βœ… No muestra selector de constructora en header - βœ… Carga automΓ‘ticamente "Constructora A" - βœ… No hay dropdown visible ### CP-006: API Token Incluye Constructora **Precondiciones:** - Usuario autenticado en "Constructora B" **Pasos:** 1. Hacer request a `/api/proyectos` 2. Inspeccionar headers de la peticiΓ³n **Resultado Esperado:** - βœ… Header incluye: `X-Constructora-Id: uuid-b` - βœ… JWT token incluye claim: `constructoraId: uuid-b` - βœ… Backend aplica RLS automΓ‘ticamente --- ## πŸ”— Dependencias **Requisitos Previos:** - ET-ADM-001: Tabla `user_constructoras` implementada - ET-ADM-001: Row Level Security configurado - Context API o Zustand para estado global **APIs Necesarias:** - `GET /api/users/me/constructoras` - Lista de constructoras del usuario - `POST /api/users/me/switch-constructora` - Cambiar contexto - Todos los endpoints deben respetar `X-Constructora-Id` header **Componentes Frontend:** - ConstructoraSelector (dropdown component) - useConstructora (custom hook) - ConstructoraContext (React Context) --- ## πŸ“Š MΓ©tricas de Γ‰xito - **Tiempo de cambio:** <500ms para cambiar de constructora - **Persistencia:** 100% de casos recuerdan ΓΊltima selecciΓ³n - **Aislamiento de datos:** 0 casos de filtraciΓ³n entre constructoras - **Redirecciones correctas:** 100% redirige cuando pierde permisos --- ## πŸ”’ Consideraciones de Seguridad 1. **ValidaciΓ³n Backend:** Siempre validar que el usuario tiene acceso a la constructora solicitada 2. **RLS AutomΓ‘tico:** PostgreSQL Row Level Security filtra automΓ‘ticamente por `constructora_id` 3. **JWT Claims:** Token debe incluir `constructoraId` actual 4. **No Confiar en Frontend:** Validar permisos en cada request, no solo en UI --- **Generado:** 2025-11-20 **Estado:** βœ… Listo para desarrollo