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:
useAppQuerycarga la lectura inicial con una query key namespaced por comunidad y rol.subscribeToInfoChangesvalida cada snapshot y actualiza la caché TanStack Query en tiempo real; al desmontar el hook, se cancela la suscripción.- Las escrituras usan
useAppMutation; al asentarse, incluso con error, invalidan la query del agregado. - Si faltan comunidad, rol o usuario, la mutación se rechaza antes de invocar el servicio.
retryvuelve 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.
| Área | Operaciones |
|---|---|
| Lectura | getInfoData, subscribeToInfoChanges |
| Agregado | createInfo, updateInfoData |
| FAQ | createInfoFaq, updateInfoFaq, deleteInfoFaq |
| Contactos | createInfoContact, updateInfoContact, deleteInfoContact |
| Normas/documentos | uploadInfoStandards, 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
| Grupo | Hooks y responsabilidad |
|---|---|
| Página | useInformationPageData: query, listener realtime, mapeo, mutations y retry. |
| FAQ | useFaqTab, useCreateFaqQuestionDialog, useEditFaqQuestionDialog, useDeleteFaqQuestionDialog: lista, edición y confirmación de borrado. |
| Contactos | useContactsTab, useCreateContactDialog, useEditContactDialog, useDeleteContactDialog, useContactActionsDropdown, useContactCopy: CRUD, acciones y clipboard. |
| Documentos | useNeighborhoodRulesTab, useUploadDocumentDialog, useRenameDocumentDialog, useDeleteDocumentDialog, useDocumentActionsDropdown, useDocumentPreview: selección, carga, preview y acciones. |
| Flujo local | useWorkFlowTab: 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.
| Familia | Códigos representativos | Tratamiento en system |
|---|---|---|
| Validación | INFO_INVALID_INPUT, INFO_INVALID_UPDATE | Copy local para revisar datos. |
| Persistencia/snapshot | INFO_INVALID_DATABASE, INFO_INVALID_CREATED, INFO_INVALID_SNAPSHOT | Fallback seguro, sin detalles del SDK. |
| Negocio | INFO_NOT_FOUND, INFO_ALREADY_EXISTS | Mensaje de elemento ausente o conflicto. |
| Acceso | INFO_PERMISSION_DENIED, INFO_AUTHENTICATION_REQUIRED | Copy de permiso o sesión. |
| Infraestructura | INFO_NETWORK_ERROR, INFO_OPERATION_FAILED | Copy 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
| Capa | Cobertura |
|---|---|
| Schema | Estructura, arrays vacíos, metadata opcional, campos requeridos, email/rol y update parcial en packages/schemas/firestore/tests/info.schema.test.ts. |
| Servicio | Permisos 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. |
| Hooks | Contexto y payloads, cache/subscription/retry, dialogs de FAQ/contacto/documentos y estados locales en modules/information/hooks/**/*.test.tsx. |
| UI compartida | Visibilidad según permiso/fallback en modules/shared/components/permission-visibility-component.test.tsx. |
| Utilidades | Lí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:
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