Módulo: Documentos Legales
Scope
| Tipo de organización | Acceso |
|---|---|
| Empresa | ✅ |
| Agencia | ✅ |
| Reclutador independiente | ✅ |
| Usuario sin organización | ✅ (registro) |
Permisos por rol
| Acción | Disponible | Permiso |
|---|---|---|
| Ver Términos y Condiciones | ✅ | Público (no requiere autenticación) |
| Ver Política de Privacidad | ✅ | Público (no requiere autenticación) |
¿Qué es?
Módulo que consume los documentos legales publicados desde el backend (términos y condiciones, política de privacidad). El contenido es dinámico, bilingüe (es/en), y versionado. Se usa en el flujo de registro y es accesible desde las páginas de auth.
¿Qué puede hacer el usuario?
- Leer los Términos y Condiciones publicados
- Leer la Política de Privacidad publicada
- El contenido se resuelve en el idioma del dispositivo (via
Accept-Languageheader) - En el registro, debe leer ambos documentos antes de poder aceptar el checkbox
Flujo del usuario
En el registro
1. Usuario llega al formulario de registro
2. Ve el checkbox "Acepto los términos y condiciones y la política de privacidad"
3. El checkbox está deshabilitado hasta leer ambos documentos
4. Toca "términos y condiciones" → abre página que carga desde API
5. Lee el documento → regresa → indicador muestra ✓ leído
6. Toca "política de privacidad" → abre página que carga desde API
7. Lee el documento → regresa → indicador muestra ✓ leído
8. Ambos leídos → checkbox se habilita → marca → puede registrarse
Página independiente
1. Navega a la página de términos o privacidad
2. Se muestra loading mientras carga
3. Éxito → renderiza título, fecha y contenido completo
4. Error → muestra mensaje con botón de reintentar
Reglas de negocio
- Solo se muestran documentos con status
PUBLISHED - Si no hay documento publicado, el API retorna 404 con
LEGAL_DOCUMENT_NOT_FOUND - El locale se resuelve del header
Accept-Language(soportaesyen-US) - El contenido incluye
body(texto plano) ybodyHtml(HTML sanitizado) - Actualmente se renderiza el
bodycomo texto;bodyHtmlestá disponible para renderizado futuro - Los documentos tienen un
contentHashSHA-256 para verificar integridad/versión - En el registro, el checkbox requiere haber abierto y regresado de ambos documentos
Arquitectura
lib/features/legal_documents/
├── application/
│ ├── legal_document_cubit.dart # loadTermsAndConditions() / loadPrivacyPolicy()
│ └── legal_document_state.dart # LegalDocumentStatus enum
├── data/
│ ├── datasources/
│ │ └── legal_documents_remote_datasource.dart
│ ├── models/
│ │ └── legal_document_model.dart # fromJson
│ └── repositories/
│ └── legal_documents_repository_impl.dart
└── domain/
├── entities/
│ └── legal_document.dart # Equatable, inmutable
├── repositories/
│ └── legal_documents_repository.dart
└── usecases/
├── get_terms_and_conditions_usecase.dart
└── get_privacy_policy_usecase.dart
Las páginas de presentación viven en lib/features/auth/presentation/pages/:
terms_and_conditions_page.dartprivacy_policy_page.dart
Endpoints API (sin prefijo /api)
| Método | Endpoint | Autenticación | Descripción |
|---|---|---|---|
| GET | /legal-documents/terms-and-conditions | Público | Términos y Condiciones publicados |
| GET | /legal-documents/privacy-policy | Público | Política de Privacidad publicada |
Estructura de respuesta
{
"key": "TERMS_AND_CONDITIONS",
"version": 1,
"status": "PUBLISHED",
"locale": "es",
"title": "Términos y condiciones",
"summary": "Condiciones de uso de Contratta.",
"body": "Contenido legal completo...",
"bodyHtml": "<p>Contenido legal completo...</p>",
"contentHash": "sha256:4d4f5b9e...",
"publishedAt": "2026-07-17T19:00:00.000Z",
"effectiveAt": "2026-07-17T19:00:00.000Z"
}
Registro DI
- Datasource:
LazySingleton - Repository:
LazySingleton - Use Cases:
LazySingleton(GetTermsAndConditionsUseCase, GetPrivacyPolicyUseCase) - Cubit:
Factory(nueva instancia por página)
getIt<LegalDocumentCubit>()
Localización
El contenido viene localizado del backend según el header Accept-Language. Las etiquetas de la UI usan claves l10n existentes (registerTerms, registerPrivacy, etc.).
Estados de la UI
| Estado | Comportamiento |
|---|---|
| Loading | CircularProgressIndicator centrado |
| Success | Renderiza título, fecha efectiva y body completo |
| Error | Ícono de error + mensaje + botón "Reintentar" |