System

apps/system/modules/information

Information

Módulo de system para consultar y administrar normas del barrio, preguntas frecuentes y contactos. El flujo de obras es informativo y usa estado/constantes locales; no forma parte del agregado persistido.

Contrato de datos

La información persistida vive en communities/{communityId}/info/data, validada por infoSchema de @repo/schemas. El agregado contiene communityId, standards, faqs y contacts; cada entrada incluye id y createdBy: { userId, role }. La metadata fileName, uploadedAt y storagePath de documentos es opcional para mantener compatibilidad con registros anteriores.

@repo/schemas es la fuente de verdad para IInfo, IInfoStandard, IInfoFaq, IInfoContact, ICreateInfo e IUpdateInfo. Los tipos de UI (IContact, IFaqQuestion e IInformationDocumentSummary) representan modelos de presentación y no deben duplicar el contrato persistido.

Flujo de datos

useInformationPageData compone la UI con los servicios públicos de @repo/app-services:

  1. useAppQuery carga la lectura inicial con una query key namespaced por comunidad y rol.
  2. subscribeToInfoChanges valida cada snapshot y actualiza la caché TanStack Query en tiempo real; al desmontar el hook, se cancela la suscripción.
  3. Las escrituras usan useAppMutation; al asentarse, incluso con error, invalidan la query del agregado.
  4. Si faltan comunidad, rol o usuario, la mutación se rechaza antes de invocar el servicio. retry vuelve a consultar y reconstruye el listener que terminó.

Los componentes no importan Firebase. El servicio usa @repo/firebase-client-adapter, valida con @repo/schemas y consulta los permisos compartidos de @repo/constants.

API del servicio

Las operaciones se importan desde @repo/app-services; los códigos públicos, desde @repo/app-services/info-errors.

ÁreaOperaciones
LecturagetInfoData, subscribeToInfoChanges
AgregadocreateInfo, updateInfoData
FAQcreateInfoFaq, updateInfoFaq, deleteInfoFaq
ContactoscreateInfoContact, updateInfoContact, deleteInfoContact
Normas/documentosuploadInfoStandards, renameInfoStandard, deleteInfoStandard

Las escrituras de FAQ, contactos y metadata de documentos usan transacciones sobre el documento único. La primera creación puede inicializar el agregado vacío; editar o eliminar un id ausente produce INFO_NOT_FOUND. Las creaciones de FAQ/contacto guardan uid y rol para auditoría.

La subida carga objetos en Storage y después agrega metadata. Si falla la carga o la escritura de metadata, intenta borrar los paths intentados mediante Promise.allSettled. Al borrar una norma, elimina primero el objeto y luego su metadata; acepta storage/object-not-found y puede derivar el path desde la URL en documentos antiguos sin storagePath. La coordinación entre Firestore y Storage es compensatoria, no una transacción distribuida.

Hooks de UI

GrupoHooks y responsabilidad
PáginauseInformationPageData: query, listener realtime, mapeo, mutations y retry.
FAQuseFaqTab, useCreateFaqQuestionDialog, useEditFaqQuestionDialog, useDeleteFaqQuestionDialog: lista, edición y confirmación de borrado.
ContactosuseContactsTab, useCreateContactDialog, useEditContactDialog, useDeleteContactDialog, useContactActionsDropdown, useContactCopy: CRUD, acciones y clipboard.
DocumentosuseNeighborhoodRulesTab, useUploadDocumentDialog, useRenameDocumentDialog, useDeleteDocumentDialog, useDocumentActionsDropdown, useDocumentPreview: selección, carga, preview y acciones.
Flujo localuseWorkFlowTab: estado de etapa activa del flujo informativo.

Los hooks de formulario manejan estado de diálogos, normalización local (por ejemplo, recortar nombres) y feedback de UI; no reemplazan la validación del servicio/schema.

Validación de documentos

utils/document.utils.ts acepta PDF, JPG/JPEG y PNG; rechaza archivos vacíos, tamaño superior a 10 MiB y MIME incompatible con la extensión. Un MIME vacío se acepta cuando la extensión está permitida. Los archivos inválidos permanecen visibles con su error, pero quedan excluidos de la carga. El nombre se recorta antes de enviar y formatFileSizeBytes presenta B/KB/MB/GB.

Errores

Los servicios lanzan AppError de @repo/app-errors. INFO_ERROR_CODES define códigos estables; se preserva la causa en cause y el message es técnico y seguro, no copy de usuario.

FamiliaCódigos representativosTratamiento en system
ValidaciónINFO_INVALID_INPUT, INFO_INVALID_UPDATECopy local para revisar datos.
Persistencia/snapshotINFO_INVALID_DATABASE, INFO_INVALID_CREATED, INFO_INVALID_SNAPSHOTFallback seguro, sin detalles del SDK.
NegocioINFO_NOT_FOUND, INFO_ALREADY_EXISTSMensaje de elemento ausente o conflicto.
AccesoINFO_PERMISSION_DENIED, INFO_AUTHENTICATION_REQUIREDCopy de permiso o sesión.
InfraestructuraINFO_NETWORK_ERROR, INFO_OPERATION_FAILEDCopy de conexión o error genérico.

utils/information-error.ts traduce code y, como fallback, kind a copy en español para toasts y el estado de página. Nunca mostrar error.message directamente ni inferir categorías buscando palabras en el mensaje del proveedor.

Permisos y límites de seguridad

La lectura requiere SEE_INFORMATION_DASHBOARD; la escritura requiere EDIT_INFORMATION_DASHBOARD según el mapa de roles compartido (actualmente admin). Los asserts del servicio protegen los casos de uso del cliente, pero no son una frontera de autorización del servidor. Las reglas actuales de Firestore permiten lectura/escritura pública en Information y Storage tiene una regla global permisiva. Los tests de servicio, por tanto, no prueban aislamiento real de datos; esa garantía requiere Rules restrictivas y tests con Rules Emulator.

Tests y metodología

CapaCobertura
SchemaEstructura, arrays vacíos, metadata opcional, campos requeridos, email/rol y update parcial en packages/schemas/firestore/tests/info.schema.test.ts.
ServicioPermisos antes de efectos, CRUD, ids inexistentes, transacciones, inicialización, snapshots, unsubscribe, errores y cleanup de Storage en packages/app-services/src/info/info-service.test.ts.
HooksContexto y payloads, cache/subscription/retry, dialogs de FAQ/contacto/documentos y estados locales en modules/information/hooks/**/*.test.tsx.
UI compartidaVisibilidad según permiso/fallback en modules/shared/components/permission-visibility-component.test.tsx.
UtilidadesLímites de archivo/tamaño y mapa de errores en modules/information/utils/*.test.ts.

Los tests de servicio usan adapters mockeados: verifican el caso de uso, no las Rules del emulador. Comandos desde la raíz del monorepo:

bash
pnpm --filter system test
pnpm --filter @repo/app-services test:run
pnpm --filter @repo/schemas test:run
pnpm --filter system lint
pnpm --filter system exec tsc --noEmit
pnpm --filter @repo/app-services lint
pnpm --filter @repo/app-services type-check
pnpm --filter @repo/schemas lint
pnpm --filter @repo/schemas type-check