# Análisis de Mocks de Staff App vs. Schema de Data Connect

Este documento realiza una comparación detallada entre las estructuras de datos (mocks) utilizadas en la aplicación de Staff y las entidades definidas en el schema de GraphQL de Firebase Data Connect. El objetivo es identificar discrepancias, proponer soluciones y asegurar la consistencia entre el frontend y el backend.

---

## 1. Perfil de Leaderboard (`_profiles`)

- **Archivo Mock:** `lib/screens/worker/worker_profile/level_up/leaderboard_screen.dart`
- **Entidad Data Connect más cercana:** `Staff` (`dataconnect/schema/staff.gql`)

### Comparación Campo por Campo

| Campo (Mock App) | Campo (Schema GQL `Staff`) | Recomendación |
| :--- | :--- | :--- |
| `id` | `id` | ✅ **Match.** |
| `name` | `employeeName` | ⚠️ **Diferencia de nombre.** Renombrar `name` a `employeeName` en la app. |
| `photo_url` | `(No existe)` | ❌ **Campo faltante.** El schema de `Staff` no tiene un campo para URL de foto. Se debe agregar. |
| `xp` | `(No existe)` | ❌ **Campo faltante.** Relacionado con gamificación. Proponer `experiencePoints: Int`. |
| `level` | `(No existe)` | ❌ **Campo faltante.** Relacionado con gamificación. Proponer `level: String`. |
| `user_id` | `(No existe)` | ⚠️ **Diferencia conceptual.** El schema `Staff` tiene `vendorId` y `email`. Aclarar si `user_id` corresponde al `id` del `User` o `Staff`. |

### Recomendaciones

1.  **En la app (Flutter):**
    - Cambiar el nombre del campo `name` a `employeeName` para que coincida con el schema.
2.  **En el schema (`staff.gql`):**
    - Agregar los campos para la gamificación y el perfil.

    ```graphql
    type Staff @table(name: "staffs") {
      # ... campos existentes
      profilePictureUrl: String
      experiencePoints: Int @default(expr: "0")
      level: String
    }
    ```

---

## 2. Conversaciones (`_conversations`)

- **Archivo Mock:** `lib/screens/worker/worker_profile/support/messages_screen.dart`
- **Entidades Data Connect más cercanas:** `Conversation` (`conversation.gql`) y `Message` (`message.gql`).

El mock aplana la información de ambas entidades.

### Comparación de `Conversation`

| Campo (Mock App) | Campo (Schema GQL `Conversation`) | Recomendación |
| :--- | :--- | :--- |
| `sender_id` | `participants` | ⚠️ **Diferencia de estructura.** El mock asume una conversación 1-a-1, mientras `participants` es un `String` (JSON) con un array de IDs. La app debe adaptarse para manejar múltiples participantes. |
| `sender_name` | (No existe directamente) | ℹ️ **Dato derivado.** Este dato debe obtenerse consultando la entidad `Staff` o `User` con el ID del participante. |
| `lastMessage` | (No existe directamente) | ℹ️ **Dato derivado.** Este debe ser el campo `content` del último `Message` asociado a la `conversationId`. La app debe consultar los mensajes. |
| `lastTime` | `updatedDate` | ✅ **Match conceptual.** `updatedDate` en `Conversation` debería actualizarse con cada nuevo mensaje. La app puede usar este campo. |
| `unread` | (No existe) | ❌ **Campo faltante y complejo.** El conteo de no leídos es por usuario. El schema actual no lo soporta. El campo `readBy` en `Message` podría usarse para calcular esto, pero es ineficiente. Se requiere un rediseño. |
| `messages` | (Corresponde a la entidad `Message`) | ℹ️ **Relación.** La app debe hacer una query separada para obtener los `Message` donde `conversationId` coincida. |

### Comparación de `Message` (anidado en el mock)

| Campo (Mock App) | Campo (Schema GQL `Message`) | Recomendación |
| :--- | :--- | :--- |
| `content` | `content` | ✅ **Match.** |
| `sender_id` | `createdBy` / `senderName` | ✅ **Match conceptual.** El schema tiene `createdBy` (ID del usuario) y `senderName`. La app debe usar estos campos. |

### Recomendaciones

1.  **En la app (Flutter):**
    - Adaptar la lógica para manejar `participants` como un array.
    - Implementar la obtención de `sender_name` y `lastMessage` a través de queries adicionales.
    - Eliminar la consulta de mensajes anidada y realizar una consulta separada por `conversationId`.
2.  **En el schema (`conversation.gql` y `message.gql`):**
    - El manejo de `unread` es un desafío. Una solución a largo plazo podría ser una nueva tabla `ConversationReadStatus` que vincule `(userId, conversationId, lastReadTimestamp)`. Por ahora, se puede calcular en el cliente.
    - El schema actual es funcional pero requiere que el cliente orqueste varias llamadas.

---

## 3. Hojas de Tiempo (`_timesheets`)

- **Archivo Mock:** `lib/screens/worker/worker_profile/finances/time_card_screen.dart`
- **Entidades Data Connect más cercanas:** `Shift` (`shift.gql`) y `Event` (`event.gql`).

El mock es una vista aplanada que combina información de un turno (`Shift`) y del evento (`Event`) al que pertenece.

### Comparación Campo por Campo

| Campo (Mock App) | Campo (Schema GQL `Shift`/`Event`) | Recomendación |
| :--- | :--- | :--- |
| `id` | `Shift.id` | ✅ **Match.** |
| `shift_id` | `Shift.id` | ✅ **Match.** (Redundante en el mock). |
| `date` | `Shift.startDate` | ✅ **Match conceptual.** Usar `startDate`. |
| `actual_start` | (No existe) | ❌ **Campo faltante.** El schema de `Shift` necesita campos para el check-in/out real. Proponer `actualStartTime: Timestamp`. |
| `actual_end` | (No existe) | ❌ **Campo faltante.** Proponer `actualEndTime: Timestamp`. |
| `total_hours` | (No existe) | ℹ️ **Dato derivado.** Debe calcularse en la app o en el backend a partir de `actualStartTime` y `actualEndTime`. |
| `hourly_rate` | `Staff.rate` / `Event.rate`? | ⚠️ **Requiere clarificación.** La tarifa puede depender del staff, del evento o del rol en el turno. El schema de `Shift` debería tener un campo `rate`. |
| `total_pay` | (No existe) | ℹ️ **Dato derivado.** Calcular `total_hours * hourly_rate`. |
| `status` | `Shift.status`? | ⚠️ **Ambigüedad.** `Shift` no tiene `status`, pero `Event` sí. El estado del pago (`pending`, `approved`, `paid`) es un concepto diferente. Se necesita un campo `paymentStatus` en `Shift`. |
| `shift_title` | `Shift.shiftName` | ✅ **Match.** |
| `client_name` | `Event.clientName` o `Business.name` | ℹ️ **Dato relacionado.** Se debe obtener a través del `eventId` en el `Shift` para luego consultar el `Event` o `Business` asociado. |
| `location` | `Event.eventLocation` | ℹ️ **Dato relacionado.** Obtener del `Event` asociado. |

### Recomendaciones

1.  **En la app (Flutter):**
    - La app debe realizar una consulta que una datos de `Shift` y su `Event` relacionado para construir esta vista.
    - Calcular campos derivados como `total_hours` y `total_pay`.
2.  **En el schema (`shift.gql`):**
    - Agregar campos cruciales para el registro de tiempo y pago.

    ```graphql
    type Shift @table(name: "shifts") {
      # ... campos existentes
      actualStartTime: Timestamp
      actualEndTime: Timestamp
      rate: Float
      paymentStatus: String # O un enum: PENDING, APPROVED, PAID, DISPUTED
    }
    ```

---

## 4. Certificados (`_certificates`)

- **Archivo Mock:** `lib/screens/worker/worker_profile/compliance/certificates_screen.dart`
- **Entidad Data Connect más cercana:** `Certification` (`certification.gql`)

### Comparación Campo por Campo

| Campo (Mock App) | Campo (Schema GQL `Certification`) | Recomendación |
| :--- | :--- | :--- |
| `id` | `id` | ✅ **Match.** |
| `name` | `certificationName` | ⚠️ **Diferencia de nombre.** Renombrar `name` a `certificationName` en la app. |
| `icon` / `color` | (No existe) | ℹ️ **Lógica de UI.** Estos campos son para la visualización y deben manejarse en el frontend. No pertenecen al schema. |
| `description` | (No existe) | ❌ **Campo faltante.** El schema podría beneficiarse de un campo descriptivo. Proponer `description: String`. |
| `status` | `status` y `validationStatus` | ✅ **Match conceptual.** El schema tiene dos campos de estado. La app debe combinar o decidir cuál mostrar. `CertificationStatus` (`CURRENT`, `EXPIRED`) parece el correcto. |
| `expiry` | `expiryDate` | ✅ **Match conceptual.** El tipo de dato debe ser consistente (el mock usa String?, el schema `String!`). |

### Recomendaciones

1.  **En la app (Flutter):**
    - Cambiar `name` por `certificationName`.
    - Mapear los valores de `status` del schema al estado que la UI espera.
2.  **En el schema (`certification.gql`):**
    - Considerar añadir un campo opcional para la descripción.

    ```graphql
    type Certification @table(name: "certification") {
      # ... campos existentes
      description: String
    }
    ```

---

## 5. Contactos de Emergencia (`_contacts`)

- **Archivo Mock:** `lib/screens/worker/worker_profile/onboarding/emergency_contact_screen.dart`
- **Entidad Data Connect más cercana:** **Ninguna.**

No existe una entidad para almacenar contactos de emergencia.

### Recomendaciones

1.  **En el schema:**
    - Crear una nueva entidad `EmergencyContact`. Debería estar vinculada a un `Staff`.

    ```graphql
    # En un nuevo archivo: dataconnect/schema/emergencyContact.gql

    type EmergencyContact @table(name: "emergency_contacts") {
      id: UUID! @default(expr: "uuidV4()")
      staffId: UUID!          # FK a la tabla Staff
      name: String!
      phone: String!
      relationship: String    # Ejemplo: "Spouse", "Parent", "Friend"
      createdDate: Timestamp @default(expr: "request.time")
      updatedDate: Timestamp @default(expr: "request.time")
    }
    ```
    - Se debe decidir si esta información se almacena como un array de `jsonb` en la tabla `Staff` o como una tabla separada. Una tabla separada es más limpia y escalable.

---

## Conclusiones Generales

1.  **Aplanamiento de Datos:** La app de Flutter tiende a usar estructuras de datos aplanadas que combinan campos de múltiples entidades de Data Connect. Esto es normal para las vistas de UI, pero requiere que la capa de datos de la app realice las consultas y uniones necesarias.
2.  **Campos Faltantes Críticos:** Se han identificado campos faltantes importantes, especialmente en `Shift` (para el control de horas y pagos) y `Staff` (para gamificación y perfil).
3.  **Nomenclatura:** Hay inconsistencias menores en los nombres de los campos. La recomendación general es **alinear la app con los nombres del schema de Data Connect**, que es la fuente de verdad.
4.  **Nuevas Entidades:** Se necesitan nuevas entidades como `EmergencyContact`. Otras estructuras mock (`_benefitsData`, `_attireOptions`, `_courses`, etc.) también requerirán probablemente sus propias tablas y schemas en Data Connect.
