Paquete Compartido @repo/shared-types
Objetivo
Section titled “Objetivo”Definir contratos canónicos de dominio, auth y API para evitar drift entre apps.
Archivos
Section titled “Archivos”auth.tsapi.tsdomain.tsdashboard.tsagenda.tscartera.tscatalog.tsinteractions.tscampaigns.tskanban.tschats-unassigned.tsmobile-auth.tscustom-fields.tsindex.ts
Notas de adopción (web + native)
Section titled “Notas de adopción (web + native)”- Todos los módulos CRM priorizados (dashboard, agenda, campañas, chats sin asignar, interacciones, kanban) consumen contratos desde este paquete.
PaginatedResponse<T>se mantiene por compatibilidad con consumidores actuales de web.- Se evita volver a declarar tipos de dominio en
apps/web/app/typeso en pantallas deapps/native. auth.tses el contrato canónico de acceso BoostAPI para web y mobile.mobile-auth.tsdebe mantenerse alineado aauth.tsy reutilizar sus tipos, no duplicarlos.BoostAuthUserincluyeroleName,roleSource, IDs de rol ypermissions; eso permite persistir el mismo payload normalizado en ambas apps.roleNamees la normalización camelCase derole_name, que sigue viniendo de BoostAPI como slug estable.mobile-auth.tsya no debe inventar una variante más pobre del contrato; debe reexportar o extender el shape canónico deauth.ts.
Contrato reciente de cartera
Section titled “Contrato reciente de cartera”CarteraItemincluyegroupIdpara preservar la relación operativa con BoostAPI incluso si la UI renderiza por lead/cliente.CarteraAssignSellerInputusagroupIds: string[]y noleadIds.CarteraAssignSellerResultdevuelve:assignedGroupIdsskippedGroupIds
cartera.tstambién define ahora el contrato oficial de contacto para el detalle:CarteraContactCarteraContactChannelCarteraUpdateContactInput
CarteraContactincluye también:hasCustomFieldValuescustomFieldValuesCount
cartera.tstambién define ahora el contrato de la pestañaFacturas:CarteraInvoiceCarteraGroupInvoicesPageCarteraGroupInvoiceDetailResponseCarteraInvoiceDetailLineCarteraInvoicesSettingsCarteraInvoicesEmptyState
- Esos campos existen para que web y native no tengan que adivinar si un contacto necesita cargar extras
record_type = contact. - En facturas, el contrato compartido preserva:
- lotes paginados por día
invoiceNumberpara la columna principal de 3 líneasinvoiceUrlcomo dato de referencia devuelto por backend- un segundo contrato de drawer por
invoiceId, para cargar líneas solo cuando el usuario abre el detalle - campos raw + normalizados en cada línea del drawer, para que web/native usen
code/name/trackingName/expirationLabelsin perder compatibilidad con el backend actual beneficiaryNamescomo array para soportar render simple o burbuja multi-valor sin reinventar mapeos por plataforma
- Ese contrato existe para reflejar el dominio real
groups -> leads -> contactssin depender del bloque legacyContactos. - Esa forma es intencional para alinear web y native con la regla de negocio actual:
- la mutación de asignación desde cartera es por grupo
- la propagación a leads/contactos la resuelve backend
Regla para consumidores
Section titled “Regla para consumidores”- Si una pantalla permite multi-selección de filas de cartera, debe transformar esos rows a
groupIdsúnicos antes de llamar la mutación. - Ningún consumidor debe reintroducir una variante local basada en
leadIds, porque eso rompe la semántica compartida entre apps.
Contrato reciente de custom-fields
Section titled “Contrato reciente de custom-fields”custom-fields.tsdefine los contratos compartidos para:- estructura (
CustomFieldType,CustomFieldGroup,CustomField,CustomFieldOption) - valores reales (
CustomFieldValue,UpsertCustomFieldValueInput,UpsertGroupCustomFieldValuesInput,UpsertContactCustomFieldValuesInput) - catálogos (
CurrencyCatalogOption,DepartmentCatalogOption,MunicipalityCatalogOption) - media firmada (
CustomFieldMediaUploadInput,CustomFieldMediaUploadResult,CustomFieldMediaDownloadInput,CustomFieldMediaDownloadResult)
- estructura (
- El detalle de cartera usa esos tipos para renderizar
Informacion personalizada del clientecon campos dinámicos reales de BoostAPI. CustomFieldGroupyCustomField.groupya incluyenrecord_type; eso permite separar en frontend:- secciones de
group - secciones de
contact
- secciones de
CustomFieldValue.record_typeya contemplagroup,leadycontact, y cartera detalle ya usa tantogroupcomocontact.clientno se modela comorecord_typeaparte dentro del paquete; la semántica compartida sigue siendoleadconzauru_id.CustomField.settingssigue tipado comoRecord<string, unknown> | nulla propósito para no romper compatibilidad cuando backend agrega keys nuevas por fase.- Bajo ese criterio, el paquete ya puede transportar sin cambios estructurales:
readonlyoverride_permission_codecontexts
- Regla futura para consumidores:
- podrán leer
settings.readonlypara bloquear edición - no deberán asumir que
contextsya filtra pantallas en backend; por ahora solo es preparación de contrato
- podrán leer
- Para media (
image,video,pdf), el valor persistido se modela con:value_text=object_keyvalue_json= metadata del archivo
- Para media optimizada,
custom-fields.tstambién preserva el contrato explícito de render:render_statecurrent_assetactive_uploadhas_persisted_asset
- Los consumidores deben respetar
settings.depends_on_custom_field_idpara camposmunicipalityy limpiar/revalidar el valor dependiente cuando cambie eldepartment.
