15 KiB
Análisis Comparativo: Mocks de Staff App vs. Schema de Data Connect
Este documento detalla el análisis comparativo entre las estructuras de datos mock utilizadas en la aplicación de Staff y las entidades definidas en el schema de Firebase Data Connect.
El objetivo es identificar discrepancias, proponer alineaciones y asegurar la consistencia del modelo de datos.
1. _calculateDuration() (de lib/widgets/shift_card.dart)
- Estructura Mock:
{ 'hours': int, 'breakTime': String, } - Entidad Data Connect más cercana: No aplica.
- Análisis:
- Esta estructura es un tipo de retorno de una función de utilidad en la UI, no representa una entidad persistente.
- Calcula valores derivados (
horas,breakTime) a partir de los datos de un turno (Shift).
- Recomendación:
- No se requiere ninguna acción. Es correcto que la lógica de la UI maneje este tipo de cálculos derivados.
2. createWorkerProfile y _profile (Múltiples archivos)
-
Estructura Mock (agregada):
{ 'full_name': String, // Corresponde a 'employeeName' en Staff 'bio': String, // No existe en Staff 'preferred_locations': List<String>, // Podría ser 'hubLocation' o 'eventLocation' 'max_distance_miles': double, // No existe en Staff 'skills': List<String>, // No existe en Staff, ¿quizás 'track' o 'position'? 'industries': List<String>, // No existe en Staff 'level': String, // No existe en Staff 'photo_url': String, // No existe en Staff 'total_shifts': int, // Existe como 'totalShifts' 'average_rating': double, // Existe como 'rating' 'on_time_rate': int, // No existe en Staff 'no_show_count': int, // Existe como 'noShowCount' 'cancellation_count': int, // Existe como 'cancellationCount' 'reliability_score': int, // Existe como 'reliabilityScore' 'phone': String, // Existe como 'phone' } -
Entidad Data Connect más cercana:
Staff(staff.gql) -
Comparación Campo por Campo:
Campo Mock Campo Staff(Data Connect)Coincidencia Notas full_nameemployeeNameParcial El nombre es diferente pero el propósito es el mismo. bionotesParcial noteses un campo genérico,bioes más específico.preferred_locationshubLocation,eventLocationParcial El schema tiene campos de texto, el mock una lista. max_distance_miles- No No existe un campo equivalente. skillstrack,position,position2Parcial skillses una lista, mientras que el schema tiene campos fijos.industries- No No existe un campo equivalente. levelprofileTypeParcial leveles un string,profileTypees unEnum. El propósito es similar.photo_url- No No existe un campo para la foto. total_shiftstotalShiftsDirecta Coincidencia exacta. average_ratingratingDirecta El propósito es el mismo. on_time_rate- No No existe un campo equivalente. no_show_countnoShowCountDirecta Coincidencia exacta. cancellation_countcancellationCountDirecta Coincidencia exacta. reliability_scorereliabilityScoreDirecta Coincidencia exacta. phonephone,contactNumberDirecta Existen dos campos de teléfono. Alinear a uno. -
Diferencias y Recomendaciones:
- Nombres de Campos: Se recomienda que la app se alinee con los nombres de Data Connect para mantener la consistencia (e.g., usar
employeeNameen lugar defull_name). - Campos Faltantes en
Staff:photo_url: Crítico. Se debe agregar un campophotoUrl: Stringa la entidadStaff.bio: Se puede usar el camponoteso agregar un campobio: Stringsi se considera una propiedad fundamental.max_distance_miles: Recomendar agregarmaxTravelDistance: Float.on_time_rate: Recomendar agregaronTimeRate: Float.
- Manejo de Listas (skills, industries, preferred_locations):
- Opción A (Recomendada): Usar campos de tipo
jsonbpara almacenar estas listas.scalar Any # En Staff skills: Any @col(dataType: "jsonb") industries: Any @col(dataType: "jsonb") preferredLocations: Any @col(dataType: "jsonb") - Opción B: Crear nuevas entidades y relaciones (e.g.,
StaffSkill,StaffIndustry), lo cual es más complejo pero más estructurado.
- Opción A (Recomendada): Usar campos de tipo
- Nombres de Campos: Se recomienda que la app se alinee con los nombres de Data Connect para mantener la consistencia (e.g., usar
3. _user (de worker_profile_screen.dart y personal_info_screen.dart)
-
Estructura Mock:
{ 'full_name': String, 'email': String, 'photo_url': String, } -
Entidad Data Connect más cercana:
User(user.gql) -
Comparación Campo por Campo:
Campo Mock Campo User(Data Connect)Coincidencia Notas full_namefullNameDirecta Coincidencia de propósito, diferencia de naming. emailemailDirecta Coincidencia exacta. photo_url- No No existe un campo para la foto en User. -
Diferencias y Recomendaciones:
- El mock
_userparece ser una combinación de datos de la entidadUser(auth) yStaff(perfil). photo_urlpertenece al perfil del trabajador, no a su registro de autenticación. Debería estar en la entidadStaff(ver punto anterior).- La app debe obtener el
emailyfullNamede la entidadUsery el resto de la información de perfil de la entidadStaff.
- El mock
4. _contacts (de emergency_contact_screen.dart)
- Estructura Mock:
{ 'name': String, 'phone': String, 'relationship': String } - Entidad Data Connect más cercana: No existe.
- Análisis:
- Esta información es específica del perfil de un trabajador.
- No justifica una nueva tabla en la base de datos, ya que un contacto de emergencia no es una entidad independiente.
- Recomendación:
- Agregar un campo
emergencyContacts: Any @col(dataType: "jsonb")a la entidadStaff. Este campo almacenaría un array de objetos JSON con la estructura del mock.
- Agregar un campo
5. _conversations y messages (de messages_screen.dart)
- Estructura Mock:
// Conversación { 'sender_id': String, 'sender_name': String, 'lastMessage': String, 'lastTime': DateTime, 'unread': int, 'messages': [ ... ] // Lista de mensajes } // Mensaje { 'content': String, 'sender_id': String, } - Entidades Data Connect más cercanas:
Conversation(conversation.gql) yMessage(message.gql). - Análisis y Comparación:
- Data Connect tiene un modelo normalizado con dos entidades separadas:
ConversationyMessage, relacionadas porconversationId. - El mock presenta un modelo desnormalizado, donde los mensajes están anidados dentro de la conversación.
- Discrepancias:
Conversation:- El mock tiene
sender_idysender_name, mientras que el schema tieneparticipants(un array de IDs). - El mock tiene
lastMessage,lastTimeyunread, que son datos derivados. El schema deConversationno los tiene, y deberían calcularse o recuperarse del último mensaje asociado.
- El mock tiene
Message:- El schema tiene
senderNameycreatedBy(ID), mientras que el mock solo tienesender_id.
- El schema tiene
- Data Connect tiene un modelo normalizado con dos entidades separadas:
- Recomendaciones:
- Alinear la App: La app debe adaptarse al modelo de Data Connect.
- Primero, obtener la lista de
Conversationpara el usuario actual. - Luego, para cada conversación, obtener el último
Messagepara mostrarlastMessageylastTime. - El conteo de
unreaddeberá calcularse en la app o agregar un campo derivado enConversation.
- Primero, obtener la lista de
- Schema
Message: El schema deMessageestá bien, pero podría beneficiarse de un camposenderIdexplícito además decreatedBypara mayor claridad.
- Alinear la App: La app debe adaptarse al modelo de Data Connect.
6. _timesheets (de time_card_screen.dart)
- Estructura Mock:
{ 'id': String, 'shift_id': String, 'date': String, 'actual_start': String, 'actual_end': String, 'total_hours': double, 'hourly_rate': double, 'total_pay': double, 'status': String, 'shift_title': String, 'client_name': String, 'location': String, } - Entidad Data Connect más cercana:
Assignment(assignment.gql) yShift(shift.gql). - Análisis:
- Un
timesheetparece ser el resultado de unAssignmentcompletado. - Combina información de múltiples entidades: el
Assignment(estado, rol), elShift(fechas, título) yStaff(tarifa/rate).
- Un
- Recomendaciones:
- Crear una nueva entidad
TimeCard: Esta es la opción más limpia para representar una hoja de tiempo.type TimeCard @table(name: "time_cards") { id: UUID! @default(expr: "uuidV4()") assignmentId: UUID! staffId: UUID! actualStart: Timestamp! actualEnd: Timestamp! totalHours: Float! hourlyRate: Float! totalPay: Float! status: String # Podría ser un Enum (PENDING, APPROVED, PAID) # ... otros campos relevantes } - Extender
Assignment: Agregar los camposactualStart,actualEnd,totalHours, etc., a la entidadAssignment. Esto es menos ideal, ya que mezcla la planificación (scheduledStart) con la ejecución. - App: La app deberá construir la vista del
timesheetcombinando datos deTimeCard(oAssignmentextendido),ShiftyOrder(paraclient_name).
- Crear una nueva entidad
7. _certificates y _courses (Múltiples archivos)
- Estructura Mock (agregada):
{ 'id': String, 'name': String, // o 'title' 'description': String, 'status': String, // 'CURRENT', 'EXPIRED', 'PENDING' 'expiry': String?, 'duration_minutes': int, 'xp_reward': int, 'progress_percent': int, 'completed': bool, } - Entidad Data Connect más cercana:
Certification(certification.gql). - Análisis y Comparación:
- La entidad
Certificationde Data Connect ya cubre los aspectos más importantes: nombre, tipo, estado y fecha de expiración. - Los mocks
_coursesy_trainingsintroducen conceptos de gamificación (xp_reward) y seguimiento del progreso (progress_percent,duration_minutes) que no están enCertification.
- La entidad
- Recomendaciones:
- Diferenciar Entidades: Es probable que se necesiten dos entidades:
Certification: Para documentos oficiales y de cumplimiento (la entidad actual funciona bien).TrainingCourse: Una nueva entidad para los cursos de "Krow University".type TrainingCourse @table(name: "training_courses") { id: UUID! @default(expr: "uuidV4()") title: String! description: String durationMinutes: Int xpReward: Int # ... otros campos } type StaffTrainingProgress @table(name: "staff_training_progress") { id: UUID! @default(expr: "uuidV4()") staffId: UUID! courseId: UUID! progressPercent: Int completed: Boolean }
- App: La app deberá consumir de
Certificationpara la pantalla de "Certificados" y de las nuevas entidades para "Krow University".
- Diferenciar Entidades: Es probable que se necesiten dos entidades:
8. _recentPayments (de payments_screen.dart y earnings_screen.dart)
- Estructura Mock:
{ 'date': String, 'amount': double, 'status': String, 'title': String, // Nombre del turno/evento 'location': String, 'workedTime': String, 'hours': int, 'rate': int, } - Entidad Data Connect más cercana:
Invoice(invoice.gql). - Análisis:
- La entidad
Invoicerepresenta una factura con un monto total y un estado, pero no el detalle de los turnos que la componen. - El mock
_recentPaymentses una vista agregada que combina datos de un pago/factura con detalles del trabajo realizado.
- La entidad
- Recomendaciones:
- El modelo de datos debería incluir una relación entre
Invoicey losTimeCard(oAssignment) que la componen.# En la nueva entidad TimeCard invoiceId: UUID # Se asigna cuando se incluye en una factura - La app deberá:
- Obtener los
Invoicepagados para unStaff. - Para cada
Invoice, obtener losTimeCardasociados. - Con los
TimeCard, obtener los detalles delShiftyOrderpara construir la vista completa que se ve en el mock.
- Obtener los
- El modelo de datos debería incluir una relación entre
9. _recentActivity (de clock_in_screen.dart)
- Estructura Mock:
{ 'date': DateTime, 'start': String, 'end': String, 'hours': String, } - Entidad Data Connect más cercana:
ActivityLog(activityLog.gql) - Análisis:
- La entidad
ActivityLogestá diseñada para registrar eventos genéricos (EVENT_CREATED,STAFF_ASSIGNED), pero no específicamente los eventos de "clock-in" y "clock-out". - Los datos del mock (
start,end,hours) se solapan con la entidadTimeCardpropuesta anteriormente.
- La entidad
- Recomendaciones:
- Usar
TimeCard: Los eventos declock-inyclock-outdeberían crear o actualizar un registro en la entidadTimeCard.Clock-in→ Crea unTimeCardconactualStart.Clock-out→ Actualiza elTimeCardexistente conactualEndy calculatotalHours.
ActivityLogpara Notificaciones: Se puede usarActivityLogpara notificar al usuario sobre acciones importantes (e.g., "Tu hoja de tiempo ha sido aprobada"), pero no para almacenar los datos crudos del fichaje.- La app debería mostrar el historial de
TimeCarden la pantalla declock_in.
- Usar
Conclusión General y Pasos a Seguir
La validación revela que, si bien hay una base sólida, se necesitan varias actualizaciones en el schema de Data Connect para dar soporte completo a las funcionalidades de la app de Staff.
Acciones recomendadas (en orden de prioridad):
- Actualizar
Staff:- Añadir campos faltantes:
photoUrl,maxTravelDistance,onTimeRate,bio. - Añadir campos
jsonbparaskills,industries,preferredLocationsyemergencyContacts. - Alinear el naming en la app a
employeeName.
- Añadir campos faltantes:
- Crear
TimeCard:- Definir e implementar la nueva entidad
TimeCardpara gestionar los fichajes y las horas trabajadas.
- Definir e implementar la nueva entidad
- Crear Entidades de
Training:- Crear
TrainingCourseyStaffTrainingProgresspara la funcionalidad de "Krow University".
- Crear
- Alinear la App:
- Refactorizar los servicios de la app para que consuman el SDK de Data Connect según el modelo de datos actualizado (especialmente para conversaciones y pagos).
- Ajustar la UI para construir las vistas a partir de múltiples entidades relacionadas en lugar de un único mock desnormalizado.