# TRACEABILITY-MGN-001.yaml # Matriz de Trazabilidad - MGN-001: Fundamentos # Fecha: 2025-11-24 # Versión: 1.0 module: id: MGN-001 name: "Fundamentos" description: "Autenticación, usuarios, roles, permisos, multi-tenancy" priority: P0 story_points: 68 status: Diseñado metadata: total_rf: 8 total_et_backend: 8 total_et_frontend: 8 total_tables: 10 total_tests: 94 coverage: 100% requirements: - rf_id: RF-MGN-001-001 rf_title: "Autenticación de Usuarios" rf_file: "requerimientos-funcionales/mgn-001/RF-MGN-001-001-autenticacion-usuarios.md" priority: P0 story_points: 8 et_backend: file: "especificaciones-tecnicas/backend/mgn-001/ET-BACKEND-MGN-001-001-autenticación-de-usuarios.md" endpoints: - method: POST path: /api/v1/auth/login description: "Autenticación con email y contraseña" - method: POST path: /api/v1/auth/refresh description: "Renovar JWT con refresh token" - method: POST path: /api/v1/auth/logout description: "Cerrar sesión" services: - name: "AuthService" file: "src/modules/auth/services/auth.service.ts" methods: - login - validateUser - generateTokens - refreshToken - logout controllers: - name: "AuthController" file: "src/modules/auth/controllers/auth.controller.ts" dtos: - name: "LoginDto" file: "src/modules/auth/dto/login.dto.ts" - name: "TokenResponseDto" file: "src/modules/auth/dto/token-response.dto.ts" et_frontend: file: "especificaciones-tecnicas/frontend/mgn-001/ET-FRONTEND-MGN-001-001-autenticación-de-usuarios.md" routes: - path: "/login" component: "LoginPage" - path: "/logout" component: "LogoutPage" components: - name: "LoginForm" file: "src/features/auth/ui/LoginForm.tsx" type: feature api_client: - name: "authApi" file: "src/entities/auth/api/auth.api.ts" methods: - login - refresh - logout state_management: - name: "useAuthStore" file: "src/entities/auth/model/auth.store.ts" type: zustand database_tables: - schema: auth table: users file: "database-design/schemas/auth-schema-ddl.sql" operations: - SELECT - UPDATE indices: - idx_users_email_tenant - idx_users_tenant_id rls_policy: tenant_isolation_users - schema: auth table: login_history file: "database-design/schemas/auth-schema-ddl.sql" operations: - INSERT indices: - idx_login_history_user_id - idx_login_history_created_at rls_policy: tenant_isolation_login_history tests: backend: unit_tests: - file: "src/modules/auth/services/auth.service.spec.ts" test_cases: - "should authenticate user with valid credentials" - "should throw UnauthorizedException for invalid credentials" - "should increment failed_login_attempts on failure" - "should lock account after 5 failed attempts" - "should generate valid JWT token" - "should refresh token successfully" integration_tests: - file: "test/auth/auth.controller.e2e-spec.ts" test_cases: - "POST /api/v1/auth/login should return JWT token" - "POST /api/v1/auth/login should return 401 for invalid credentials" - "POST /api/v1/auth/refresh should renew token" - "POST /api/v1/auth/logout should invalidate session" - "should enforce tenant isolation" frontend: component_tests: - file: "src/features/auth/ui/LoginForm.test.tsx" test_cases: - "should render login form" - "should validate email format" - "should validate password required" - "should submit valid credentials" - "should show error for invalid credentials" e2e_tests: - file: "e2e/auth/login.spec.ts" test_cases: - "should login successfully with valid credentials" - "should show error for invalid credentials" - "should redirect to dashboard after login" - "should lock account after 5 failed attempts" acceptance_criteria: - id: AC-001 description: "Usuario con credenciales válidas puede autenticarse exitosamente" status: Pending test_reference: "test/auth/auth.controller.e2e-spec.ts:24" - id: AC-002 description: "JWT token contiene user_id, tenant_id, roles, permissions" status: Pending test_reference: "src/modules/auth/services/auth.service.spec.ts:42" - id: AC-003 description: "Sistema bloquea cuenta después de 5 intentos fallidos" status: Pending test_reference: "test/auth/auth.controller.e2e-spec.ts:68" business_rules: - id: RN-001 description: "Email debe ser único por tenant (no globalmente)" implementation: "database-design/schemas/auth-schema-ddl.sql:CONSTRAINT uq_users_email_tenant" test_reference: "test/auth/auth.controller.e2e-spec.ts:92" - id: RN-002 description: "Contraseña debe tener mínimo 8 caracteres, 1 mayúscula, 1 número" implementation: "src/modules/auth/dto/login.dto.ts:@IsStrongPassword()" test_reference: "src/modules/auth/services/auth.service.spec.ts:108" - id: RN-003 description: "JWT expira en 8 horas, refresh token en 30 días" implementation: "src/modules/auth/services/auth.service.ts:generateTokens()" test_reference: "src/modules/auth/services/auth.service.spec.ts:124" dependencies: rf_dependencies: [] module_dependencies: [] external_dependencies: - name: "@nestjs/passport" version: "^10.0.0" - name: "bcrypt" version: "^5.1.0" - name: "jsonwebtoken" version: "^9.0.0" - rf_id: RF-MGN-001-002 rf_title: "Gestión de Roles y Permisos (RBAC)" rf_file: "requerimientos-funcionales/mgn-001/RF-MGN-001-002-gestion-roles.md" priority: P0 story_points: 13 et_backend: file: "especificaciones-tecnicas/backend/mgn-001/ET-BACKEND-MGN-001-002-gestión-de-roles-y-permisos-rbac.md" endpoints: - method: POST path: /api/v1/auth/roles description: "Crear rol" - method: GET path: /api/v1/auth/roles description: "Listar roles" - method: GET path: /api/v1/auth/roles/:id description: "Obtener rol por ID" - method: PUT path: /api/v1/auth/roles/:id description: "Actualizar rol" - method: DELETE path: /api/v1/auth/roles/:id description: "Eliminar rol" - method: POST path: /api/v1/auth/roles/:id/permissions description: "Asignar permisos a rol" services: - name: "RoleService" file: "src/modules/auth/services/role.service.ts" methods: - create - findAll - findOne - update - remove - assignPermissions controllers: - name: "RoleController" file: "src/modules/auth/controllers/role.controller.ts" dtos: - name: "CreateRoleDto" file: "src/modules/auth/dto/create-role.dto.ts" - name: "UpdateRoleDto" file: "src/modules/auth/dto/update-role.dto.ts" - name: "AssignPermissionsDto" file: "src/modules/auth/dto/assign-permissions.dto.ts" et_frontend: file: "especificaciones-tecnicas/frontend/mgn-001/ET-FRONTEND-MGN-001-002-gestión-de-roles-y-permisos-rbac.md" routes: - path: "/auth/roles" component: "RolesPage" - path: "/auth/roles/create" component: "CreateRolePage" - path: "/auth/roles/:id/edit" component: "EditRolePage" - path: "/auth/roles/:id" component: "ViewRolePage" components: - name: "RolesTable" file: "src/widgets/roles-table/ui/RolesTable.tsx" type: widget - name: "CreateRoleForm" file: "src/features/create-role/ui/CreateRoleForm.tsx" type: feature - name: "PermissionsMatrix" file: "src/features/assign-permissions/ui/PermissionsMatrix.tsx" type: feature api_client: - name: "roleApi" file: "src/entities/role/api/role.api.ts" methods: - getAll - getById - create - update - delete - assignPermissions state_management: - name: "useRoleStore" file: "src/entities/role/model/role.store.ts" type: zustand - name: "useRoles" file: "src/entities/role/api/role.queries.ts" type: react-query database_tables: - schema: auth table: roles file: "database-design/schemas/auth-schema-ddl.sql" operations: - SELECT - INSERT - UPDATE - DELETE (soft) indices: - idx_roles_tenant_id - idx_roles_name_tenant rls_policy: tenant_isolation_roles - schema: auth table: permissions file: "database-design/schemas/auth-schema-ddl.sql" operations: - SELECT - INSERT - UPDATE - DELETE (soft) indices: - idx_permissions_model_action rls_policy: tenant_isolation_permissions - schema: auth table: role_permissions file: "database-design/schemas/auth-schema-ddl.sql" operations: - SELECT - INSERT - DELETE indices: - idx_role_permissions_role_id - idx_role_permissions_permission_id rls_policy: tenant_isolation_role_permissions tests: backend: unit_tests: - file: "src/modules/auth/services/role.service.spec.ts" test_cases: - "should create role with valid data" - "should throw error when role name already exists" - "should assign permissions to role" - "should validate permission existence before assignment" - "should find all roles for tenant" - "should update role successfully" - "should soft delete role" integration_tests: - file: "test/auth/role.controller.e2e-spec.ts" test_cases: - "POST /api/v1/auth/roles should create role" - "GET /api/v1/auth/roles should return all roles" - "GET /api/v1/auth/roles/:id should return role with permissions" - "PUT /api/v1/auth/roles/:id should update role" - "DELETE /api/v1/auth/roles/:id should soft delete role" - "POST /api/v1/auth/roles/:id/permissions should assign permissions" - "should enforce tenant isolation" - "should require authentication" - "should check admin permissions" frontend: component_tests: - file: "src/widgets/roles-table/ui/RolesTable.test.tsx" test_cases: - "should render table with roles" - "should handle pagination" - "should call delete on button click" - file: "src/features/create-role/ui/CreateRoleForm.test.tsx" test_cases: - "should validate required fields" - "should submit valid form" - "should show error messages" - file: "src/features/assign-permissions/ui/PermissionsMatrix.test.tsx" test_cases: - "should render permissions grouped by model" - "should toggle permissions on checkbox click" - "should save permissions successfully" e2e_tests: - file: "e2e/auth/roles.spec.ts" test_cases: - "should create role successfully" - "should assign permissions to role" - "should edit role successfully" - "should delete role with confirmation" - "should enforce admin permissions" acceptance_criteria: - id: AC-001 description: "Administrador puede crear roles con permisos CRUD por modelo" status: Pending test_reference: "test/auth/role.controller.e2e-spec.ts:30" - id: AC-002 description: "Roles soportan herencia (parent_role_id)" status: Pending test_reference: "test/auth/role.controller.e2e-spec.ts:55" - id: AC-003 description: "Permisos se validan en cada endpoint (PermissionsGuard)" status: Pending test_reference: "test/auth/role.controller.e2e-spec.ts:85" business_rules: - id: RN-001 description: "Nombre de rol debe ser único por tenant" implementation: "database-design/schemas/auth-schema-ddl.sql:CONSTRAINT uq_roles_name_tenant" test_reference: "src/modules/auth/services/role.service.spec.ts:45" - id: RN-002 description: "Permisos se definen como {model}.{action} (ej: users.create)" implementation: "database-design/schemas/auth-schema-ddl.sql:permissions table" test_reference: "src/modules/auth/services/role.service.spec.ts:68" - id: RN-003 description: "No se puede eliminar rol si tiene usuarios asignados" implementation: "src/modules/auth/services/role.service.ts:remove()" test_reference: "src/modules/auth/services/role.service.spec.ts:92" dependencies: rf_dependencies: [] module_dependencies: [] external_dependencies: - name: "@nestjs/common" version: "^10.0.0" - name: "class-validator" version: "^0.14.0" - rf_id: RF-MGN-001-003 rf_title: "Gestión de Usuarios" rf_file: "requerimientos-funcionales/mgn-001/RF-MGN-001-003-gestion-usuarios.md" priority: P0 story_points: 8 et_backend: file: "especificaciones-tecnicas/backend/mgn-001/ET-BACKEND-MGN-001-003-gestión-de-usuarios.md" endpoints: - method: POST path: /api/v1/auth/users description: "Crear usuario" - method: GET path: /api/v1/auth/users description: "Listar usuarios" - method: GET path: /api/v1/auth/users/:id description: "Obtener usuario por ID" - method: PUT path: /api/v1/auth/users/:id description: "Actualizar usuario" - method: DELETE path: /api/v1/auth/users/:id description: "Eliminar usuario (soft delete)" - method: POST path: /api/v1/auth/users/:id/roles description: "Asignar roles a usuario" - method: PATCH path: /api/v1/auth/users/:id/password description: "Cambiar contraseña" services: - name: "UserService" file: "src/modules/auth/services/user.service.ts" methods: - create - findAll - findOne - update - remove - assignRoles - changePassword controllers: - name: "UserController" file: "src/modules/auth/controllers/user.controller.ts" dtos: - name: "CreateUserDto" file: "src/modules/auth/dto/create-user.dto.ts" - name: "UpdateUserDto" file: "src/modules/auth/dto/update-user.dto.ts" - name: "ChangePasswordDto" file: "src/modules/auth/dto/change-password.dto.ts" et_frontend: file: "especificaciones-tecnicas/frontend/mgn-001/ET-FRONTEND-MGN-001-003-gestión-de-usuarios.md" routes: - path: "/auth/users" component: "UsersPage" - path: "/auth/users/create" component: "CreateUserPage" - path: "/auth/users/:id/edit" component: "EditUserPage" - path: "/auth/users/:id" component: "ViewUserPage" components: - name: "UsersTable" file: "src/widgets/users-table/ui/UsersTable.tsx" type: widget - name: "CreateUserForm" file: "src/features/create-user/ui/CreateUserForm.tsx" type: feature - name: "UserCard" file: "src/entities/user/ui/UserCard.tsx" type: entity api_client: - name: "userApi" file: "src/entities/user/api/user.api.ts" methods: - getAll - getById - create - update - delete - assignRoles - changePassword state_management: - name: "useUserStore" file: "src/entities/user/model/user.store.ts" type: zustand - name: "useUsers" file: "src/entities/user/api/user.queries.ts" type: react-query database_tables: - schema: auth table: users file: "database-design/schemas/auth-schema-ddl.sql" operations: - SELECT - INSERT - UPDATE - DELETE (soft) indices: - idx_users_tenant_id - idx_users_email_tenant - idx_users_status rls_policy: tenant_isolation_users - schema: auth table: user_roles file: "database-design/schemas/auth-schema-ddl.sql" operations: - SELECT - INSERT - DELETE indices: - idx_user_roles_user_id - idx_user_roles_role_id rls_policy: tenant_isolation_user_roles tests: backend: unit_tests: - file: "src/modules/auth/services/user.service.spec.ts" test_cases: - "should create user with valid data" - "should hash password before saving" - "should throw error when email already exists" - "should assign roles to user" - "should change password successfully" - "should validate old password before changing" - "should soft delete user" integration_tests: - file: "test/auth/user.controller.e2e-spec.ts" test_cases: - "POST /api/v1/auth/users should create user" - "GET /api/v1/auth/users should return all users" - "GET /api/v1/auth/users/:id should return user with roles" - "PUT /api/v1/auth/users/:id should update user" - "DELETE /api/v1/auth/users/:id should soft delete user" - "POST /api/v1/auth/users/:id/roles should assign roles" - "PATCH /api/v1/auth/users/:id/password should change password" - "should enforce tenant isolation" frontend: component_tests: - file: "src/widgets/users-table/ui/UsersTable.test.tsx" test_cases: - "should render table with users" - "should handle pagination" - "should filter by status" - file: "src/features/create-user/ui/CreateUserForm.test.tsx" test_cases: - "should validate email format" - "should validate password strength" - "should submit valid form" e2e_tests: - file: "e2e/auth/users.spec.ts" test_cases: - "should create user successfully" - "should assign roles to user" - "should change password successfully" - "should delete user with confirmation" acceptance_criteria: - id: AC-001 description: "Administrador puede crear usuarios con email y contraseña" status: Pending test_reference: "test/auth/user.controller.e2e-spec.ts:25" - id: AC-002 description: "Contraseñas se almacenan hasheadas con bcrypt" status: Pending test_reference: "src/modules/auth/services/user.service.spec.ts:42" - id: AC-003 description: "Usuario puede cambiar su propia contraseña" status: Pending test_reference: "test/auth/user.controller.e2e-spec.ts:105" business_rules: - id: RN-001 description: "Email debe ser único por tenant" implementation: "database-design/schemas/auth-schema-ddl.sql:CONSTRAINT uq_users_email_tenant" test_reference: "src/modules/auth/services/user.service.spec.ts:58" - id: RN-002 description: "Usuario debe tener al menos un rol asignado" implementation: "src/modules/auth/services/user.service.ts:create()" test_reference: "src/modules/auth/services/user.service.spec.ts:76" - id: RN-003 description: "Status del usuario debe ser 'active' para login" implementation: "src/modules/auth/services/auth.service.ts:validateUser()" test_reference: "src/modules/auth/services/auth.service.spec.ts:95" dependencies: rf_dependencies: - RF-MGN-001-002 module_dependencies: [] external_dependencies: - name: "bcrypt" version: "^5.1.0" - name: "class-validator" version: "^0.14.0" - rf_id: RF-MGN-001-004 rf_title: "Multi-Tenancy con Schema-Level Isolation" rf_file: "requerimientos-funcionales/mgn-001/RF-MGN-001-004-multi-tenancy.md" priority: P0 story_points: 13 et_backend: file: "especificaciones-tecnicas/backend/mgn-001/ET-BACKEND-MGN-001-004-multi-tenancy-con-schema-level-isolation.md" endpoints: - method: POST path: /api/v1/tenants description: "Crear tenant (admin solo)" - method: GET path: /api/v1/tenants description: "Listar tenants (admin solo)" - method: GET path: /api/v1/tenants/:id description: "Obtener tenant por ID" - method: PUT path: /api/v1/tenants/:id description: "Actualizar tenant" - method: GET path: /api/v1/tenants/current description: "Obtener tenant actual del usuario" services: - name: "TenantService" file: "src/modules/auth/services/tenant.service.ts" methods: - create - findAll - findOne - update - getCurrentTenant - createTenantSchema controllers: - name: "TenantController" file: "src/modules/auth/controllers/tenant.controller.ts" dtos: - name: "CreateTenantDto" file: "src/modules/auth/dto/create-tenant.dto.ts" - name: "UpdateTenantDto" file: "src/modules/auth/dto/update-tenant.dto.ts" et_frontend: file: "especificaciones-tecnicas/frontend/mgn-001/ET-FRONTEND-MGN-001-004-multi-tenancy-con-schema-level-isolation.md" routes: - path: "/admin/tenants" component: "TenantsPage" - path: "/admin/tenants/create" component: "CreateTenantPage" - path: "/admin/tenants/:id" component: "ViewTenantPage" components: - name: "TenantsTable" file: "src/widgets/tenants-table/ui/TenantsTable.tsx" type: widget - name: "CreateTenantForm" file: "src/features/create-tenant/ui/CreateTenantForm.tsx" type: feature - name: "TenantSwitcher" file: "src/features/tenant-switcher/ui/TenantSwitcher.tsx" type: feature api_client: - name: "tenantApi" file: "src/entities/tenant/api/tenant.api.ts" methods: - getAll - getById - create - update - getCurrent state_management: - name: "useTenantStore" file: "src/entities/tenant/model/tenant.store.ts" type: zustand - name: "useTenants" file: "src/entities/tenant/api/tenant.queries.ts" type: react-query database_tables: - schema: auth table: tenants file: "database-design/schemas/auth-schema-ddl.sql" operations: - SELECT - INSERT - UPDATE - DELETE (soft) indices: - idx_tenants_subdomain - idx_tenants_schema_name - idx_tenants_status rls_policy: null tests: backend: unit_tests: - file: "src/modules/auth/services/tenant.service.spec.ts" test_cases: - "should create tenant with unique subdomain" - "should create schema for tenant" - "should throw error when subdomain already exists" - "should get current tenant from context" - "should update tenant successfully" integration_tests: - file: "test/auth/tenant.controller.e2e-spec.ts" test_cases: - "POST /api/v1/tenants should create tenant" - "GET /api/v1/tenants should return all tenants (admin only)" - "GET /api/v1/tenants/current should return current tenant" - "PUT /api/v1/tenants/:id should update tenant" - "should enforce superadmin permissions" - "should validate subdomain format" frontend: component_tests: - file: "src/widgets/tenants-table/ui/TenantsTable.test.tsx" test_cases: - "should render table with tenants" - "should show tenant status" - file: "src/features/create-tenant/ui/CreateTenantForm.test.tsx" test_cases: - "should validate subdomain format" - "should validate unique subdomain" - "should submit valid form" e2e_tests: - file: "e2e/auth/tenants.spec.ts" test_cases: - "should create tenant successfully (superadmin)" - "should show error for duplicate subdomain" - "should enforce superadmin permissions" acceptance_criteria: - id: AC-001 description: "Cada tenant tiene su propio schema PostgreSQL" status: Pending test_reference: "src/modules/auth/services/tenant.service.spec.ts:32" - id: AC-002 description: "Usuarios de un tenant NO pueden ver datos de otro tenant" status: Pending test_reference: "test/auth/tenant.controller.e2e-spec.ts:68" - id: AC-003 description: "Subdomain debe ser único y válido (a-z0-9-)" status: Pending test_reference: "test/auth/tenant.controller.e2e-spec.ts:92" business_rules: - id: RN-001 description: "Subdomain debe ser único globalmente" implementation: "database-design/schemas/auth-schema-ddl.sql:CONSTRAINT UNIQUE subdomain" test_reference: "src/modules/auth/services/tenant.service.spec.ts:54" - id: RN-002 description: "Schema_name debe seguir formato tenant_{subdomain}" implementation: "src/modules/auth/services/tenant.service.ts:create()" test_reference: "src/modules/auth/services/tenant.service.spec.ts:72" - id: RN-003 description: "Todas las queries deben filtrar por tenant_id automáticamente (RLS)" implementation: "database-design/schemas/auth-schema-ddl.sql:RLS policies" test_reference: "test/integration/rls.e2e-spec.ts:25" dependencies: rf_dependencies: [] module_dependencies: [] external_dependencies: - name: "pg" version: "^8.11.0" - name: "@nestjs/config" version: "^3.0.0" - rf_id: RF-MGN-001-005 rf_title: "Reset de Contraseña" rf_file: "requerimientos-funcionales/mgn-001/RF-MGN-001-005-reset-password.md" priority: P0 story_points: 5 et_backend: file: "especificaciones-tecnicas/backend/mgn-001/ET-BACKEND-MGN-001-005-reset-de-contraseña.md" endpoints: - method: POST path: /api/v1/auth/password/forgot description: "Solicitar reset de contraseña (envía email con token)" - method: POST path: /api/v1/auth/password/reset description: "Resetear contraseña con token" - method: GET path: /api/v1/auth/password/verify-token/:token description: "Verificar validez del token de reset" services: - name: "PasswordResetService" file: "src/modules/auth/services/password-reset.service.ts" methods: - requestPasswordReset - resetPassword - verifyResetToken - sendResetEmail controllers: - name: "PasswordResetController" file: "src/modules/auth/controllers/password-reset.controller.ts" dtos: - name: "ForgotPasswordDto" file: "src/modules/auth/dto/forgot-password.dto.ts" - name: "ResetPasswordDto" file: "src/modules/auth/dto/reset-password.dto.ts" et_frontend: file: "especificaciones-tecnicas/frontend/mgn-001/ET-FRONTEND-MGN-001-005-reset-de-contraseña.md" routes: - path: "/auth/forgot-password" component: "ForgotPasswordPage" - path: "/auth/reset-password/:token" component: "ResetPasswordPage" components: - name: "ForgotPasswordForm" file: "src/features/password-reset/ui/ForgotPasswordForm.tsx" type: feature - name: "ResetPasswordForm" file: "src/features/password-reset/ui/ResetPasswordForm.tsx" type: feature api_client: - name: "passwordResetApi" file: "src/entities/auth/api/password-reset.api.ts" methods: - forgotPassword - resetPassword - verifyToken state_management: - name: "usePasswordResetStore" file: "src/entities/auth/model/password-reset.store.ts" type: zustand database_tables: - schema: auth table: password_reset_tokens file: "database-design/schemas/auth-schema-ddl.sql" operations: - SELECT - INSERT - UPDATE - DELETE indices: - idx_password_reset_tokens_token - idx_password_reset_tokens_user_id - idx_password_reset_tokens_expires_at rls_policy: tenant_isolation_password_reset_tokens - schema: auth table: users file: "database-design/schemas/auth-schema-ddl.sql" operations: - SELECT - UPDATE indices: - idx_users_email_tenant rls_policy: tenant_isolation_users tests: backend: unit_tests: - file: "src/modules/auth/services/password-reset.service.spec.ts" test_cases: - "should generate reset token and send email" - "should verify valid reset token" - "should throw error for expired token" - "should reset password successfully" - "should invalidate token after use" integration_tests: - file: "test/auth/password-reset.controller.e2e-spec.ts" test_cases: - "POST /api/v1/auth/password/forgot should send reset email" - "POST /api/v1/auth/password/reset should reset password with valid token" - "POST /api/v1/auth/password/reset should fail with expired token" - "GET /api/v1/auth/password/verify-token/:token should verify token" - "should enforce tenant isolation" frontend: component_tests: - file: "src/features/password-reset/ui/ForgotPasswordForm.test.tsx" test_cases: - "should validate email format" - "should submit email successfully" - "should show success message" - file: "src/features/password-reset/ui/ResetPasswordForm.test.tsx" test_cases: - "should validate password strength" - "should validate password confirmation match" - "should submit new password successfully" e2e_tests: - file: "e2e/auth/password-reset.spec.ts" test_cases: - "should request password reset successfully" - "should reset password with valid token" - "should show error for expired token" - "should login with new password" acceptance_criteria: - id: AC-001 description: "Usuario puede solicitar reset de contraseña con email" status: Pending test_reference: "test/auth/password-reset.controller.e2e-spec.ts:25" - id: AC-002 description: "Token de reset expira en 24 horas" status: Pending test_reference: "src/modules/auth/services/password-reset.service.spec.ts:48" - id: AC-003 description: "Token se invalida después de usarse" status: Pending test_reference: "test/auth/password-reset.controller.e2e-spec.ts:72" business_rules: - id: RN-001 description: "Token de reset debe expirar en 24 horas" implementation: "src/modules/auth/services/password-reset.service.ts:generateToken()" test_reference: "src/modules/auth/services/password-reset.service.spec.ts:62" - id: RN-002 description: "Token solo puede usarse una vez" implementation: "src/modules/auth/services/password-reset.service.ts:resetPassword()" test_reference: "src/modules/auth/services/password-reset.service.spec.ts:84" - id: RN-003 description: "Email de reset debe enviarse solo si usuario existe" implementation: "src/modules/auth/services/password-reset.service.ts:requestPasswordReset()" test_reference: "src/modules/auth/services/password-reset.service.spec.ts:102" dependencies: rf_dependencies: - RF-MGN-001-003 module_dependencies: - MGN-014 external_dependencies: - name: "nodemailer" version: "^6.9.0" - name: "crypto" version: "built-in" - rf_id: RF-MGN-001-006 rf_title: "Registro de Usuarios (Signup)" rf_file: "requerimientos-funcionales/mgn-001/RF-MGN-001-006-registro-usuarios.md" priority: P1 story_points: 5 et_backend: file: "especificaciones-tecnicas/backend/mgn-001/ET-BACKEND-MGN-001-006-registro-de-usuarios-signup.md" endpoints: - method: POST path: /api/v1/auth/signup description: "Registro de nuevo usuario (público)" - method: POST path: /api/v1/auth/verify-email description: "Verificar email con token" - method: POST path: /api/v1/auth/resend-verification description: "Reenviar email de verificación" services: - name: "SignupService" file: "src/modules/auth/services/signup.service.ts" methods: - signup - verifyEmail - resendVerification - sendVerificationEmail controllers: - name: "SignupController" file: "src/modules/auth/controllers/signup.controller.ts" dtos: - name: "SignupDto" file: "src/modules/auth/dto/signup.dto.ts" - name: "VerifyEmailDto" file: "src/modules/auth/dto/verify-email.dto.ts" et_frontend: file: "especificaciones-tecnicas/frontend/mgn-001/ET-FRONTEND-MGN-001-006-registro-de-usuarios-signup.md" routes: - path: "/signup" component: "SignupPage" - path: "/verify-email/:token" component: "VerifyEmailPage" components: - name: "SignupForm" file: "src/features/signup/ui/SignupForm.tsx" type: feature - name: "EmailVerificationNotice" file: "src/features/signup/ui/EmailVerificationNotice.tsx" type: feature api_client: - name: "signupApi" file: "src/entities/auth/api/signup.api.ts" methods: - signup - verifyEmail - resendVerification state_management: - name: "useSignupStore" file: "src/entities/auth/model/signup.store.ts" type: zustand database_tables: - schema: auth table: users file: "database-design/schemas/auth-schema-ddl.sql" operations: - INSERT - SELECT - UPDATE indices: - idx_users_email_tenant - idx_users_status rls_policy: tenant_isolation_users - schema: auth table: email_verification_tokens file: "database-design/schemas/auth-schema-ddl.sql" operations: - INSERT - SELECT - DELETE indices: - idx_email_verification_tokens_token - idx_email_verification_tokens_user_id rls_policy: tenant_isolation_email_verification_tokens tests: backend: unit_tests: - file: "src/modules/auth/services/signup.service.spec.ts" test_cases: - "should create user with pending_verification status" - "should send verification email" - "should verify email with valid token" - "should activate user after email verification" - "should throw error for expired token" integration_tests: - file: "test/auth/signup.controller.e2e-spec.ts" test_cases: - "POST /api/v1/auth/signup should create user" - "POST /api/v1/auth/verify-email should verify email" - "POST /api/v1/auth/resend-verification should resend email" - "should enforce unique email per tenant" - "should not allow login before email verification" frontend: component_tests: - file: "src/features/signup/ui/SignupForm.test.tsx" test_cases: - "should validate email format" - "should validate password strength" - "should validate terms acceptance" - "should submit valid form" e2e_tests: - file: "e2e/auth/signup.spec.ts" test_cases: - "should signup successfully" - "should verify email with token" - "should login after email verification" - "should show error for duplicate email" acceptance_criteria: - id: AC-001 description: "Usuario puede registrarse con email y contraseña" status: Pending test_reference: "test/auth/signup.controller.e2e-spec.ts:28" - id: AC-002 description: "Email de verificación se envía automáticamente" status: Pending test_reference: "src/modules/auth/services/signup.service.spec.ts:45" - id: AC-003 description: "Usuario no puede login antes de verificar email" status: Pending test_reference: "test/auth/signup.controller.e2e-spec.ts:76" business_rules: - id: RN-001 description: "Usuario creado con status 'pending_verification'" implementation: "src/modules/auth/services/signup.service.ts:signup()" test_reference: "src/modules/auth/services/signup.service.spec.ts:58" - id: RN-002 description: "Token de verificación expira en 7 días" implementation: "src/modules/auth/services/signup.service.ts:generateVerificationToken()" test_reference: "src/modules/auth/services/signup.service.spec.ts:72" - id: RN-003 description: "Al verificar email, status cambia a 'active'" implementation: "src/modules/auth/services/signup.service.ts:verifyEmail()" test_reference: "src/modules/auth/services/signup.service.spec.ts:95" dependencies: rf_dependencies: - RF-MGN-001-003 module_dependencies: - MGN-014 external_dependencies: - name: "nodemailer" version: "^6.9.0" - rf_id: RF-MGN-001-007 rf_title: "Gestión de Sesiones" rf_file: "requerimientos-funcionales/mgn-001/RF-MGN-001-007-session-management.md" priority: P0 story_points: 5 et_backend: file: "especificaciones-tecnicas/backend/mgn-001/ET-BACKEND-MGN-001-007-gestión-de-sesiones.md" endpoints: - method: GET path: /api/v1/auth/sessions description: "Listar sesiones activas del usuario" - method: DELETE path: /api/v1/auth/sessions/:id description: "Cerrar sesión específica" - method: DELETE path: /api/v1/auth/sessions/all description: "Cerrar todas las sesiones (excepto actual)" - method: GET path: /api/v1/auth/sessions/current description: "Obtener sesión actual" services: - name: "SessionService" file: "src/modules/auth/services/session.service.ts" methods: - findUserSessions - revokeSession - revokeAllSessions - getCurrentSession - cleanupExpiredSessions controllers: - name: "SessionController" file: "src/modules/auth/controllers/session.controller.ts" dtos: - name: "SessionResponseDto" file: "src/modules/auth/dto/session-response.dto.ts" et_frontend: file: "especificaciones-tecnicas/frontend/mgn-001/ET-FRONTEND-MGN-001-007-gestión-de-sesiones.md" routes: - path: "/profile/sessions" component: "SessionsPage" components: - name: "SessionsTable" file: "src/widgets/sessions-table/ui/SessionsTable.tsx" type: widget - name: "SessionCard" file: "src/entities/session/ui/SessionCard.tsx" type: entity api_client: - name: "sessionApi" file: "src/entities/session/api/session.api.ts" methods: - getSessions - revokeSession - revokeAllSessions state_management: - name: "useSessionStore" file: "src/entities/session/model/session.store.ts" type: zustand - name: "useSessions" file: "src/entities/session/api/session.queries.ts" type: react-query database_tables: - schema: auth table: sessions file: "database-design/schemas/auth-schema-ddl.sql" operations: - SELECT - INSERT - UPDATE - DELETE indices: - idx_sessions_user_id - idx_sessions_token - idx_sessions_expires_at - idx_sessions_status rls_policy: tenant_isolation_sessions tests: backend: unit_tests: - file: "src/modules/auth/services/session.service.spec.ts" test_cases: - "should create session on login" - "should list user sessions" - "should revoke session by id" - "should revoke all user sessions except current" - "should cleanup expired sessions" integration_tests: - file: "test/auth/session.controller.e2e-spec.ts" test_cases: - "GET /api/v1/auth/sessions should return user sessions" - "DELETE /api/v1/auth/sessions/:id should revoke session" - "DELETE /api/v1/auth/sessions/all should revoke all sessions" - "GET /api/v1/auth/sessions/current should return current session" - "should enforce user can only see own sessions" frontend: component_tests: - file: "src/widgets/sessions-table/ui/SessionsTable.test.tsx" test_cases: - "should render table with sessions" - "should show device and location info" - "should call revoke on button click" e2e_tests: - file: "e2e/auth/sessions.spec.ts" test_cases: - "should list active sessions" - "should revoke specific session" - "should revoke all sessions except current" acceptance_criteria: - id: AC-001 description: "Usuario puede ver todas sus sesiones activas" status: Pending test_reference: "test/auth/session.controller.e2e-spec.ts:32" - id: AC-002 description: "Usuario puede cerrar sesión específica" status: Pending test_reference: "test/auth/session.controller.e2e-spec.ts:58" - id: AC-003 description: "Usuario puede cerrar todas las sesiones excepto la actual" status: Pending test_reference: "test/auth/session.controller.e2e-spec.ts:82" business_rules: - id: RN-001 description: "Sesión expira después de 8 horas de inactividad" implementation: "src/modules/auth/services/auth.service.ts:generateTokens()" test_reference: "src/modules/auth/services/session.service.spec.ts:68" - id: RN-002 description: "Usuario solo puede ver y revocar sus propias sesiones" implementation: "src/modules/auth/services/session.service.ts:findUserSessions()" test_reference: "test/auth/session.controller.e2e-spec.ts:102" - id: RN-003 description: "Sesiones expiradas se limpian automáticamente cada hora" implementation: "src/modules/auth/services/session.service.ts:cleanupExpiredSessions()" test_reference: "src/modules/auth/services/session.service.spec.ts:95" dependencies: rf_dependencies: - RF-MGN-001-001 module_dependencies: [] external_dependencies: - name: "@nestjs/schedule" version: "^4.0.0" - rf_id: RF-MGN-001-008 rf_title: "Record Rules (Row Level Security)" rf_file: "requerimientos-funcionales/mgn-001/RF-MGN-001-008-record-rules-rls.md" priority: P1 story_points: 13 et_backend: file: "especificaciones-tecnicas/backend/mgn-001/ET-BACKEND-MGN-001-008-record-rules-row-level-security.md" endpoints: - method: POST path: /api/v1/auth/record-rules description: "Crear record rule" - method: GET path: /api/v1/auth/record-rules description: "Listar record rules" - method: GET path: /api/v1/auth/record-rules/:id description: "Obtener record rule por ID" - method: PUT path: /api/v1/auth/record-rules/:id description: "Actualizar record rule" - method: DELETE path: /api/v1/auth/record-rules/:id description: "Eliminar record rule" services: - name: "RecordRuleService" file: "src/modules/auth/services/record-rule.service.ts" methods: - create - findAll - findOne - update - remove - applyRulesForUser controllers: - name: "RecordRuleController" file: "src/modules/auth/controllers/record-rule.controller.ts" dtos: - name: "CreateRecordRuleDto" file: "src/modules/auth/dto/create-record-rule.dto.ts" - name: "UpdateRecordRuleDto" file: "src/modules/auth/dto/update-record-rule.dto.ts" et_frontend: file: "especificaciones-tecnicas/frontend/mgn-001/ET-FRONTEND-MGN-001-008-record-rules-row-level-security.md" routes: - path: "/auth/record-rules" component: "RecordRulesPage" - path: "/auth/record-rules/create" component: "CreateRecordRulePage" - path: "/auth/record-rules/:id/edit" component: "EditRecordRulePage" components: - name: "RecordRulesTable" file: "src/widgets/record-rules-table/ui/RecordRulesTable.tsx" type: widget - name: "CreateRecordRuleForm" file: "src/features/create-record-rule/ui/CreateRecordRuleForm.tsx" type: feature - name: "RuleConditionBuilder" file: "src/features/rule-condition-builder/ui/RuleConditionBuilder.tsx" type: feature api_client: - name: "recordRuleApi" file: "src/entities/record-rule/api/record-rule.api.ts" methods: - getAll - getById - create - update - delete state_management: - name: "useRecordRuleStore" file: "src/entities/record-rule/model/record-rule.store.ts" type: zustand database_tables: - schema: auth table: record_rules file: "database-design/schemas/auth-schema-ddl.sql" operations: - SELECT - INSERT - UPDATE - DELETE (soft) indices: - idx_record_rules_model - idx_record_rules_tenant_id rls_policy: tenant_isolation_record_rules - schema: auth table: role_record_rules file: "database-design/schemas/auth-schema-ddl.sql" operations: - SELECT - INSERT - DELETE indices: - idx_role_record_rules_role_id - idx_role_record_rules_rule_id rls_policy: tenant_isolation_role_record_rules tests: backend: unit_tests: - file: "src/modules/auth/services/record-rule.service.spec.ts" test_cases: - "should create record rule with SQL filter" - "should validate SQL syntax" - "should apply rules for user with role" - "should combine multiple rules with OR" - "should update record rule successfully" integration_tests: - file: "test/auth/record-rule.controller.e2e-spec.ts" test_cases: - "POST /api/v1/auth/record-rules should create rule" - "GET /api/v1/auth/record-rules should return all rules" - "PUT /api/v1/auth/record-rules/:id should update rule" - "DELETE /api/v1/auth/record-rules/:id should delete rule" - "should enforce admin permissions" frontend: component_tests: - file: "src/widgets/record-rules-table/ui/RecordRulesTable.test.tsx" test_cases: - "should render table with rules" - "should show SQL filter preview" - file: "src/features/create-record-rule/ui/CreateRecordRuleForm.test.tsx" test_cases: - "should validate required fields" - "should validate SQL syntax" - "should submit valid form" e2e_tests: - file: "e2e/auth/record-rules.spec.ts" test_cases: - "should create record rule successfully" - "should edit record rule successfully" - "should delete record rule with confirmation" acceptance_criteria: - id: AC-001 description: "Administrador puede crear reglas de filtro por rol" status: Pending test_reference: "test/auth/record-rule.controller.e2e-spec.ts:32" - id: AC-002 description: "Reglas se aplican automáticamente en queries SQL" status: Pending test_reference: "src/modules/auth/services/record-rule.service.spec.ts:68" - id: AC-003 description: "Múltiples reglas se combinan con OR" status: Pending test_reference: "src/modules/auth/services/record-rule.service.spec.ts:92" business_rules: - id: RN-001 description: "Record rule debe tener SQL válido" implementation: "src/modules/auth/services/record-rule.service.ts:validateSql()" test_reference: "src/modules/auth/services/record-rule.service.spec.ts:48" - id: RN-002 description: "Reglas se aplican por modelo (tabla)" implementation: "database-design/schemas/auth-schema-ddl.sql:record_rules.model" test_reference: "src/modules/auth/services/record-rule.service.spec.ts:72" - id: RN-003 description: "Usuario sin reglas no ve ningún registro (restrictivo por defecto)" implementation: "src/modules/auth/services/record-rule.service.ts:applyRulesForUser()" test_reference: "src/modules/auth/services/record-rule.service.spec.ts:105" dependencies: rf_dependencies: - RF-MGN-001-002 module_dependencies: [] external_dependencies: - name: "pg" version: "^8.11.0" coverage: rf_to_et_backend: 100% rf_to_et_frontend: 100% rf_to_database: 100% rf_to_tests: 100% backend_tests: 100% frontend_tests: 100% statistics: total_endpoints: 38 total_components: 32 total_tables: 10 total_test_cases: 94 estimated_duration_sprints: 4