GUÍA DOCENTE - ISPC-WEB-2025/TodoStock-AppMovil GitHub Wiki
Este documento ha sido elaborado a solicitud del docente para sintetizar el funcionamiento integral, las decisiones de arquitectura, las credenciales de prueba y la localización de los principales artefactos del proyecto TodoStock, desarrollado por el equipo CodeLab.
Para facilitar la corrección y prueba del sistema en sus distintas capas (Web, API REST, Admin Panel y App Mobile), se detallan a continuación los entornos activos en producción y las cuentas de prueba configuradas:
| Componente | Plataforma | URL Pública | Repositorio GitHub |
|---|---|---|---|
| Frontend Web (SPA Angular 21) | Vercel | https://todo-stock.vercel.app/ | TodoStock Repo |
| Backend REST API (Django 6) | Alwaysdata | https://todostock.alwaysdata.net/api/ | TodoStock Repo |
| Panel de Administración Django | Alwaysdata | https://todostock.alwaysdata.net/admin/ | TodoStock Repo |
| Aplicación Móvil (Android Java) | Google Play / APK | Release v1.0.0 en GitHub | TodoStock-AppMovil Repo |
| Roadmap Interactivo del Proyecto | GitHub Pages | https://ispc-web-2025.github.io/TodoStock-Mobile-RoadMap/ | TodoStock-AppMovil Repo |
Para la evaluación del sistema completo se proveen las credenciales de acceso:
-
Cuenta Principal SuperAdministrador (API / Django Admin / App / Web):
-
Email / Usuario:
[email protected] -
Contraseña:
AdminPassword123! -
Rol:
ADMINISTRADOR(is_superuser=True,is_staff=True) - Permisos: Acceso completo a la API, Panel Django Admin, Dashboard Web y la Aplicación Móvil Android.
-
Email / Usuario:
-
Acceso al Roadmap Interactivo (GitHub Pages):
- URL: https://ispc-web-2025.github.io/TodoStock-Mobile-RoadMap/
-
Usuario / Username:
CodeLab -
Contraseña / Password:
RoadMap-2026-Mobile
🛡️ 2. Jerarquía de Autenticación y SuperAdministrador Django (ADR-0008)
Para responder a las observaciones sobre seguridad y niveles de acceso en el sistema, se implementó un control de acceso basado en roles (RBAC) con tres niveles de privilegio claramente definidos:
-
Jerarquía y Matriz de Permisos Administrativos:
- 👑 SuperAdministrador (
is_superuser=True): Posee control total del sistema. Es el único rol habilitado para:- Crear nuevas cuentas de nivel Administrador.
- Aprobar/aceptar solicitudes de registro pendientes de usuarios con rol Administrador.
- Editar perfiles, reasignar roles, resetear contraseñas o desactivar a otros usuarios administradores.
- Gestionar en forma global a administradores y empleados.
- 👔 Administrador Estándar (
rol = ADMINISTRADOR,is_superuser=False):-
Permiso acotado: Puede aprobar solicitudes pendientes y editar perfiles únicamente de usuarios con rol Empleado (
es_empleado). -
Restricción de seguridad: La API le bloquea de forma estricta cualquier intento de crear administradores, aprobar solicitudes pendientes de rol Administrador o editar perfiles de otros administradores, devolviendo
HTTP 403 Forbidden. - Gestiona sucursales, productos del catálogo, existencias de inventario y traslados.
-
Permiso acotado: Puede aprobar solicitudes pendientes y editar perfiles únicamente de usuarios con rol Empleado (
- 👷 Empleado / Vendedor (
es_empleado=True):- Acceso operativo para consulta de stock, traslados entre sucursales, consulta de catálogo y soporte.
- 👑 SuperAdministrador (
-
Exposición en API (
/api/usuarios/me/):- El payload del usuario autenticado expone los flags
is_superuseryes_empleado, permitiendo que tanto la Web como la App Móvil muestren la distintiva insignia visual (Super AdminvsAdministradorvsEmpleado).
- El payload del usuario autenticado expone los flags
-
Desacople de Gestión de Contraseñas:
- Se eliminó el cambio de clave desde peticiones
PUTgenerales. Se dispuso el endpoint de autoservicioPOST /api/usuarios/me/change-password/(requierepassword_actual) y el endpoint restringidoPOST /api/usuarios/<id>/reset-password/para reset administrativo de empleados.
- Se eliminó el cambio de clave desde peticiones
👥 3. Unificación Operativa de Roles a Empleado (es_empleado) (ADR-0007)
En la operatoria real de sucursales y depósitos, los colaboradores alternan constantemente entre la atención al público (ventas) y la logística interna (conteo de stock, recepción y traslado de mercadería). Exigir cuentas o perfiles separados para "Vendedor" y "Personal de Depósito" generaba una alta fricción UX (cierres y aperturas constantes de sesión en los dispositivos móviles).
-
Preservación Físico-Relacional en MySQL:
- No se eliminaron ni fusionaron los roles en la base de datos. La tabla
rolesmantiene los registros independientes:ADMINISTRADOR,VENTASyDEPOSITO. Esto evita migraciones de BD destructivas y pérdida de historial.
- No se eliminaron ni fusionaron los roles en la base de datos. La tabla
-
Abstracción Lógica en la API (
es_empleado):- El backend Django expone una propiedad calculada
@property es_empleadoen los endpoints de autenticación:@property def es_empleado(self): return self.rol is not None and self.rol.nombre.lower() in [ "empleado", "ventas", "deposito", ]
- El backend Django expone una propiedad calculada
-
Consumo Unificado en App Móvil:
- La app Android evalúa
es_empleadopara habilitar el menú de herramientas operativas (búsqueda de catálogo, escáner, control de existencias y registro de traslados).
- La app Android evalúa
-
Preparación Transparente a Futuro:
- Si en fases posteriores se decide activar permisos restrictivos (ej. alta de mercadería reservada solo a depósito), el cliente móvil simplemente evaluará el objeto
user.rol.nombredirectamente, sin requerir ningún cambio de esquema en MySQL.
- Si en fases posteriores se decide activar permisos restrictivos (ej. alta de mercadería reservada solo a depósito), el cliente móvil simplemente evaluará el objeto
Durante la validación automática de la suite de pruebas del backend en la integración continua (CI/CD ejecutado en Python 3.12 y MySQL 8.0 ante cada Pull Request hacia develop o main), se identificó una falla por respuestas HTTP 429 Too Many Requests.
-
Causa Raíz:
- La suite de pruebas ejecuta tests masivos e instantáneos de autenticación e inicio de sesión.
- La falla demostró que la política de limitación de tasa (throttling) de Django REST Framework en la API funciona correctamente al bloquear peticiones consecutivas en lapsos de tiempo cortos.
-
Evaluación de Alternativas:
-
Opción A (Descartada): Introducir pausas temporales (
sleep) entre intentos de login en las pruebas. Se descartó debido a que volvía las pruebas CI/CD extremadamente lentas. -
Opción B (Adoptada): Configurar dinámicamente
DEFAULT_THROTTLE_RATESpara desactivar el throttling exclusivamente durante la ejecución de la suite de tests.
-
Opción A (Descartada): Introducir pausas temporales (
-
Conclusión:
- Aunque no es el escenario ideal para el entorno de tests, se verificó primero que el mecanismo de protección throttling está completamente operativo en la API. Se optó por desactivarlo dinámicamente en los tests para evitar ejecuciones lentas y falsos negativos en el pipeline de GitHub Actions.
- 📊 Diagrama de Clases UML:
- Archivo de imagen: diagrama_clases.png
- Código Mermaid: diagrama-de-clases.mmd
- 🗄️ Diagrama Entidad-Relación (DER):
- Archivo de imagen: TodoStock-DER-corregido.png
- 🧩 Modelo Relacional Lógico:
- Archivo de imagen: TodoStock-Modelo relacional (lógico)-corregido3.png
Para una correcta interpretación de los diagramas UML, DER y el modelo relacional frente a la implementación final en la aplicación móvil y la API:
-
Unificación Operativa de Roles (Modelo Relacional vs. App Mobile — ADR-0007 y ADR-0008):
-
En la base de datos (MySQL / DER): Se preservan los tres roles relacionales normalizados:
ADMINISTRADOR,VENTASyDEPOSITOen la tablaroles. -
En la App Mobile: Al no haberse desarrollado un flujo exclusivo para el rol de depósito en la app, se decidió por simplicidad funcional unificarlo con el de vendedor bajo la abstracción
@property es_empleado(rol operativo "Empleado"). Para la administración, se diferencia al SuperAdministrador (is_superuser=True) frente al Administrador estándar para el control de altas y permisos.
-
En la base de datos (MySQL / DER): Se preservan los tres roles relacionales normalizados:
-
Comportamiento en Eliminación de Productos y Stock Inicial (Issue #282 / ADR-0010):
- En el backend actual, al crear un producto nuevo se generan automáticamente registros de stock en cero en todas las sucursales. Esto provocaba que el endpoint
DELETEdel backend bloqueara la eliminación física al detectar registros asociados en la tabla de stock (reportado en Issue #282). - Al detectarse cerca del cierre del sprint, se decidió no arriesgar la estabilidad del backend en producción y resolver el manejo desde el frontend mediante baja lógica (
activo = False), dejando documentada la refactorización para futuras versiones.
- En el backend actual, al crear un producto nuevo se generan automáticamente registros de stock en cero en todas las sucursales. Esto provocaba que el endpoint
-
Desactivación de Usuarios y Anonimización Pendiente (ADR-0009 / Ley 25.326):
- La baja de cuenta (voluntaria o administrativa) actualmente desactiva al usuario marcando
is_active = Falsepara bloquear el inicio de sesión (HTTP 403), conservando el registro histórico para auditoría enLogAuditoria. - La anonimización completa de los datos personales (nombre, email, DNI) quedó documentada como un Issue en el backlog para próximas etapas, al tratarse del sprint final de la materia.
- La baja de cuenta (voluntaria o administrativa) actualmente desactiva al usuario marcando
En la carpeta Docs/ de TodoStock se centralizan las especificaciones técnicas de la API REST y las guías de infraestructura:
- 📄 API_MOBILE.md:
- Especificación detallada de endpoints consumidos por la aplicación Android, estructuras JSON de solicitud/respuesta, encabezados JWT y códigos de estado HTTP.
- 🏛️ Registros de Decisiones de Arquitectura (ADR):
- ADR-0001: Filtrado de movimientos en servidor.
- ADR-0002: Registro dual de traslados entre sucursales.
- ADR-0003: Desacople de operador en movimientos.
- ADR-0004: Enforcement global de autenticación JWT.
- ADR-0005: Sucursal central y distribución jerárquica.
- ADR-0006: Arquitectura de consumo de backend desde App Mobile.
-
ADR-0007: Unificación operativa de roles Vendedor/Depósito en
es_empleado. - ADR-0008: Blindaje de jerarquía administrativa y SuperAdmin.
- ADR-0009: Modelo de log de auditoría desacoplado.
-
ADR-0010: Baja lógica de productos (
activo = False) preservando trazabilidad.
- 🚀 Guías de Despliegue y Pruebas:
- DEPLOY_ALWAYSDATA.md & GUIA_DESPLIEGUE_DJANGO_ALWAYSDATA.md: Configuración de WSGI, MySQL y variables de entorno en servidor Alwaysdata.
- DEPLOY_VERCEL.md: Despliegue continuo del Frontend Web en Vercel.
- GUIA_TESTING_API.md: Colecciones e instrucciones para pruebas de integración con Postman / cURL.
Algunos casos del Sprint 1 y del Sprint 2 fueron ejecutados por la misma persona que desarrolló la funcionalidad, por falta de tiempo. Cada uno lo indica en la columna Comentarios de la planilla de test cases.
Casos alcanzados: TC-L-03, TC-L-04 (Login), TC-SSUC-01, TC-SSUC-02 (Selección de sucursal), TC-MOV-001 a TC-MOV-007 (Movimientos), TC-CP-01 (Carga de producto), TC-C-01 (Contacto), TC-STK-001 (Stock), TC-REG-EDAD-01, TC-REG-EDAD-02 (Registro) y TC-SEG-05 (Seguridad). El bug #183 (TC-MOV-007) fue corregido y cerrado por la misma persona que lo reportó.
Para el resto del Sprint 2, las ejecuciones (TK85 a TK89) se reasignaron para que nadie ejecute casos de una funcionalidad que programó. Los casos nuevos del Registro (TC-REG-01 a 04) los diseñan y ejecutan personas distintas de quien lo programó.
Los tests automatizados (ValidadoresTest) los escribe y ejecuta quien desarrolló el código, como es habitual en las pruebas unitarias.
A partir del análisis del Docs/API_MOBILE.md y Backend/ en contraste con los servicios Retrofit implementados en la app Android nativa, se certifica el acoplamiento al 100% de los siguientes contratos HTTP:
| Módulo / Feature | Endpoint Backend Django (Backend/) |
Verbo HTTP | Servicio Android / DTOs | PR Integración |
|---|---|---|---|---|
| Autenticación JWT | /api/usuarios/login/ |
POST |
AuthApiService / LoginRequest, LoginResponse
|
PR #49, PR #160 |
| Registro de Usuarios | /api/usuarios/registro/ |
POST |
AuthApiService / RegistroRequest, RegistroResponse
|
PR #171, PR #173, PR #223, PR #283 |
| Datos de Sesión / Perfil | /api/usuarios/me/ |
GET/PATCH |
PerfilApiService / PerfilResponse, PerfilUpdateRequest
|
PR #180 |
| Baja de Cuenta (Desactivar) | /api/usuarios/desactivar/ |
POST |
PerfilApiService / BajaRequest
|
PR #195 |
| Listado de Sucursales | /api/inventario/sucursales/ |
GET |
InventarioApiService / SucursalDto
|
PR #185 |
| Stock por Sucursal | /api/inventario/productos/{id}/stock/ |
GET |
InventarioApiService / StockItemResponse
|
PR #216, PR #220 |
| Alta de Producto (Admin) | /api/inventario/productos/ |
POST |
InventarioApiService / ProductoCreateDto
|
PR #197, PR #287 |
| Catálogo y Edición (Admin) |
/api/inventario/productos/ / {id}/
|
GET/PATCH |
InventarioApiService / ProductoDto
|
PR #296 (TK39 / ADR-0010) |
| Movimiento Atómico Stock | /api/inventario/movimientos/ |
POST |
InventarioApiService / MovimientoRequest
|
PR #185 (ADR-0002) |
| Gestión de Usuarios (Admin) |
/api/usuarios/ / {id}/
|
GET/PATCH |
UsuarioApiService / UsuariosActivosFragment
|
PR #300 (TK37 / ADR-0008) |
| Contacto y Soporte | /api/contacto/ |
POST |
ContactoApiService / ContactoRequest
|
PR #192 |
- ADR-0001 (Filtrado en Servidor): El cliente Android delega el cálculo de movimientos y stock consolidado a la API Django REST para optimizar consumo de batería y datos móviles.
-
ADR-0002 (Registro Dual de Traslados): Cada transferencia de stock enviada desde
MovimientosActivitygenera en la base de datos MySQL de forma atómica una salida en la sucursal origen y una entrada en la sucursal destino. -
ADR-0004 (Enforcement Global JWT): Validado mediante
AuthInterceptoren OkHttp, inyectando la cabeceraAuthorization: Bearer <token>en todas las peticiones excepto Login, Registro y Contacto. -
ADR-0007 (Unificación Operativa
es_empleado): La app evalúa la propiedad calculada@property es_empleadoexpuesta en/api/usuarios/me/para habilitar el panel operativo único. -
ADR-0008 (Blindaje Jerárquico Admin/SuperAdmin): Reflejado en las insignias de perfil de
PerfilActivity, enUsuariosActivosFragment(PR #300) y restricción de endpoints administrativos (HTTP 403 Forbidden). -
ADR-0009 (Modelo LogAuditoria): Cada acción crítica (baja de cuenta, registro, movimiento) se registra de forma desacoplada en la tabla
LogAuditoriaen MySQL. -
ADR-0010 (Baja Lógica de Productos): Eliminación lógica (
activo = False) preservando el historial de transacciones en la base de datos MySQL.
Contrastando el código fuente con el registro de Issues:
-
Bugs de Registro (#167, #168, #169, #281): Resueltos mediante PRs #171, #173, #223, #283 incorporando la validación en cliente
Validadores.java, el ingreso directo por teclado con máscara enRegistroActivityy manejando respuestas HTTP 400/409 del backend. -
Bug de Traslados (#183 - TC-MOV-007): Resuelto en PR #185 corrigiendo la validación de stock disponible antes del envío de la petición
POST /api/inventario/movimientos/. -
Pipeline CI/CD Backend (
.github/workflows/django-tests.yml): Ejecutado en Python 3.12 con MySQL 8.0, validando la suite de 729 líneas enBackend/usuarios/tests.pyy 226 líneas enBackend/inventario/test_mobile_api.py.
🎨 8.4 Reestructuración UX, Adaptabilidad, Aprobaciones y Testing Automatizado (PRs #267, #275..#301)
-
Módulo de Ayuda e Información de App (TK40 - PR #301): Implementación de
AyudaActivity, reproductor de video tutorial adaptativo sin barras negras enComoUsarActivity(VideoViewcon preservación de segundo actual al rotar víaonSaveInstanceState) e información técnica del sistema enInfoAppActivityleyendo dinámicamente la versión desdeBuildConfig.VERSION_NAME. -
Gestión, Edición y Baja de Usuarios (TK37 - PR #300): Implementación en
UsuariosActivosFragmentyUsuarioApiServicecon diálogo modal para edición de datos y baja de usuarios respetando la jerarquía RBAC (ADR-0008). -
Pruebas de UI con Espresso y Page Objects (AUT-UI-01 - TK70 - PR #299): Automatización del flujo completo desde Login hasta el Menú Principal en
LoginFlujoTest.javautilizando Page Object Model (LoginScreen,MenuPrincipalScreen),AccessibilityChecks.enable()eIdlingResource. -
Suite Postman de Integración de API (AUT-API-02 - TK68 - PR #298): Implementación de la colección de integración de catálogo de productos e infraestructura utilitaria en
PostmanConfig.java. -
Listado, Búsqueda, Edición y Baja Lógica de Productos (TK39 - PR #296): Módulo de catálogo completo con precarga en
CargaProductoActivity(EXTRA_ID_PRODUCTO), actualización parcialPATCHe inhabilitación lógica (activo = False- ADR-0010). -
Testing de Red con MockWebServer 200 OK y Error 500 (AUT-NET-02 - TK65 - PR #295, PR #297): Implementación de
AuthRepositoryTest.javapara verificar autenticación, respuesta 200 OK, captura de fallos de servidor HTTP 500 e inestabilidad de red enResultadoLogin. -
Aprobación y Carga de Usuarios (TK109 - PR #290): Implementación de
CargarUsuarioFragmentpara la aprobación de cuentas de registro pendientes según la jerarquía RBAC (SuperAdmin aprueba Admins; Admin aprueba Empleados). -
Adaptabilidad a Pantalla Apaisada y Tablet (TK41 - PR #294): Adaptación de 11 layouts XML con
ScrollView, márgenes ajustados, centrado de botones y preservación de estado de Spinners al rotar medianteonSaveInstanceState. -
Testing Unitario de ViewModel (TK62 - PR #293): Incorporación de
LoginViewModelTest.javapara la verificación aislada de estados de inicio de sesión con repositorio simulado. -
Testing de Integración de Red con MockWebServer (TK64 - PR #292): Implementación de
ParseoRespuestasTest.javapara la simulación de servidor REST HTTP 200 OK y parseo de DTOs JSON. -
Alta de Producto con Categoría (TK23 - PR #287): Selección e integración de categoría de producto enviada a la API REST en
CargaProductoActivity. -
Refuerzo de Testing Unitario Android (TK60 / TK61 - PR #267, PR #277): Incorporación de
StockItemTest.javapara validaciones de stock bajo umbral y mappers DTO, eliminando los tests de plantilla genéricos de Android Studio. -
Ingreso Directo de Fecha por Teclado (Fix #281 - PR #283): Entrada de fecha sin modal en
RegistroActivitymediante máscara de textoDD/MM/AAAA. -
Pantallas Intermedias / Hubs Operativos (TK113 - PR #276): Integración de
MenuStockActivityyMenuMovimientosActivity. -
Reorganización del Menú Principal (TK114 - PR #275): Layout vertical accesible sin numeración estática en
MenuPrincipalActivity.