Shared Models Plan
Ecosistema completo para organización y gestión de contenido con interfaces espaciales
Librería Shared Models (Core) - Plan de Desarrollo
Propósito: Crear una librería de modelos y tipos compartidos que sirva como fuente única de verdad para todas las interfaces de datos en el workspace GoGrab.
Estado Planificado
- Tipo: Librería Nx de TypeScript (sin Angular)
- Ruta de importación:
@libs-core/shared-models - Prioridad:
Crítica- debe crearse antes que las demás librerías - Entorno: Agnóstico - compatible con cliente y servidor
- Dependencias: Ninguna (librería base del workspace)
Arquitectura Planificada
La librería implementará un sistema de modelos TypeScript puros organizados por dominios funcionales, con exportaciones granulares para optimización de bundle size y máxima reutilización.
Principios de Diseño
- TypeScript Puro: Sin dependencias de framework, solo tipos
- Tree Shaking Friendly: Exportaciones granulares por dominio
- Backward Compatible: Evolución controlada con semantic versioning
- JSDoc Completo: Documentación inline para todos los interfaces
- Strict TypeScript: Configuración estricta sin
any
Estructura del Paquete Planificada
libs/core/shared-models/
├── project.json # Configuración Nx
├── package.json # Dependencias
├── tsconfig.json # Config TypeScript base
├── tsconfig.lib.json # Config para build
├── tsconfig.spec.json # Config para tests
├── README.md # Documentación principal
├── src/
│ ├── lib/
│ │ ├── tenant/ # 📁 Dominio Tenant
│ │ │ ├── context.ts # Context interface
│ │ │ ├── config.ts # Config, UiConfig, ResourceLimits
│ │ │ ├── permissions.ts # Permissions, ModulePermissions
│ │ │ ├── features.ts # Features interface
│ │ │ ├── context-info.ts # ContextInfo para login
│ │ │ └── index.ts # Exportaciones tenant
│ │ ├── auth/ # 📁 Dominio Authentication
│ │ │ ├── user-profile.ts # UserProfile interface
│ │ │ ├── auth-state.ts # AuthState union types
│ │ │ ├── login-credentials.ts # LoginCredentials interface
│ │ │ ├── login-result.ts # LoginResult interface
│ │ │ ├── selection-result.ts # SelectionResult interface
│ │ │ ├── auth-errors.ts # AuthError types
│ │ │ └── index.ts # Exportaciones auth
│ │ ├── rbac/ # 📁 Dominio RBAC
│ │ │ ├── role.ts # Role interface
│ │ │ ├── permission.ts # Permission interface (simplificado)
│ │ │ └── index.ts # Exportaciones rbac
│ │ ├── ui/ # 📁 Dominio UI
│ │ │ ├── branding-config.ts # BrandingConfig interface
│ │ │ ├── module-config.ts # ModuleConfig interface
│ │ │ ├── user-preferences.ts # UserPreferences interface
│ │ │ ├── theme-config.ts # ThemeConfig interface
│ │ │ ├── ui-config.ts # UiConfig interface
│ │ │ └── index.ts # Exportaciones ui
│ │ ├── api/ # 📁 Dominio API
│ │ │ ├── api-response.ts # ApiResponse<T> generic
│ │ │ ├── pagination.ts # PaginationRequest, PaginationResponse
│ │ │ ├── error-response.ts # ErrorResponse interface
│ │ │ ├── request-metadata.ts # RequestMetadata interface
│ │ │ ├── filter-criteria.ts # FilterCriteria interface
│ │ │ └── index.ts # Exportaciones api
│ │ ├── common/ # 📁 Dominio Common
│ │ │ ├── base-entity.ts # BaseEntity interface
│ │ │ ├── audit-fields.ts # AuditFields interface
│ │ │ ├── date-range.ts # DateRange interface
│ │ │ ├── key-value.ts # KeyValue<T> interface
│ │ │ └── index.ts # Exportaciones common
│ │ └── index.ts # Exportación principal (barril)
│ └── test-setup.ts # Setup para tests
└── tools/
├── type-check.ts # Validación de tipos
└── docs-generator.ts # Generador de documentación
Plan de Desarrollo por Pasos
Paso 1: Creación de la Estructura Base
# Crear librería TypeScript
nx generate @nx/js:library shared-models \
--directory=libs/core \
--importPath=@libs-core/shared-models \
--strict \
--bundler=tsc \
--minimal
Paso 2: Configuración TypeScript Estricta
// tsconfig.lib.json
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"declaration": true,
"declarationMap": true,
"strict": true,
"noImplicitAny": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"exactOptionalPropertyTypes": true
},
"include": ["src/**/*.ts"],
"exclude": ["src/**/*.spec.ts"]
}
Paso 3: Implementación del Dominio Tenant
// src/lib/tenant/context.ts
/**
* Contexto completo del tenant para el cliente Angular.
* Contiene toda la información necesaria para personalizar la experiencia del usuario.
*/
export interface Context {
/** Identificador único del tenant */
tenantId: string;
/** Nombre descriptivo del tenant para mostrar en UI */
tenantName: string;
/** URL base para las APIs específicas del tenant */
apiBaseUrl: string;
/** Locale para internacionalización (ej: 'es-ES', 'en-US') */
locale: string;
/** Zona horaria del tenant (ej: 'America/Mexico_City') */
timezone: string;
/** Permisos y autorizaciones del usuario en este tenant */
permissions: Permissions;
/** Configuración específica del tenant */
configuration: Config;
/** Características habilitadas para este tenant */
features: Features;
}
// src/lib/tenant/config.ts
/**
* Configuración específica del tenant.
* Define cómo se comporta la aplicación para este tenant.
*/
export interface Config {
/** Configuración de módulos habilitados */
modules: Record<string, ModuleConfig>;
/** Configuración de interfaz de usuario */
ui: UiConfig;
/** Límites y restricciones del tenant */
limits: ResourceLimits;
}
/**
* Configuración de interfaz de usuario por tenant.
*/
export interface UiConfig {
/** Tema visual del tenant */
theme: string;
/** Configuración de marca y branding */
branding: BrandingConfig;
/** Configuración de navegación */
navigation?: NavigationConfig;
}
/**
* Límites de recursos por tenant.
*/
export interface ResourceLimits {
/** Número máximo de usuarios */
maxUsers: number;
/** Almacenamiento máximo en MB */
maxStorage: number;
/** Límite de requests por minuto */
rateLimit: number;
/** Número máximo de roles personalizados */
maxRoles: number;
}
Paso 4: Implementación del Dominio Authentication
// src/lib/auth/user-profile.ts
/**
* Perfil completo del usuario en el contexto de un tenant específico.
*/
export interface UserProfile {
/** Identificador único del usuario */
id: string;
/** ID del tenant al que pertenece este usuario */
tenantId: string;
/** Email del usuario (único por tenant) */
email: string;
/** Nombre de usuario (único por tenant) */
username: string;
/** Nombre real del usuario */
firstName: string;
/** Apellido del usuario */
lastName: string;
/** URL del avatar del usuario */
avatar?: string;
/** Roles asignados al usuario en este tenant */
roles: Role[];
/** Permisos efectivos del usuario en este tenant */
permissions: Permission[];
/** Preferencias personales del usuario */
preferences: UserPreferences;
/** Si el usuario está activo */
isActive: boolean;
/** Fecha del último login */
lastLogin?: Date;
/** Si el email está verificado */
emailVerified: boolean;
/** Si tiene 2FA habilitado */
twoFactorEnabled: boolean;
/** Fecha de creación */
createdAt: Date;
/** Fecha de última actualización */
updatedAt: Date;
}
// src/lib/auth/auth-state.ts
/**
* Estados posibles del proceso de autenticación.
*/
export type AuthState =
| 'idle' // Estado inicial
| 'authenticating' // Autenticando credenciales
| 'context_selection_required' // Necesita seleccionar tenant
| 'loading_context' // Cargando contexto del tenant
| 'authenticated' // Completamente autenticado
| 'error' // Error en el proceso
| 'expired'; // Sesión expirada
// src/lib/auth/login-result.ts
/**
* Resultado del login inicial.
* Incluye tokens básicos y lista de tenants disponibles.
*/
export interface LoginResult {
/** Token de acceso inicial */
accessToken: string;
/** Token de refresh */
refreshToken: string;
/** Información básica del usuario */
user: UserProfile;
/** Lista de tenants a los que el usuario tiene acceso */
availableTenants: ContextInfo[];
}
/**
* Información básica de un tenant para selección.
*/
export interface ContextInfo {
/** ID del tenant */
tenantId: string;
/** Nombre del tenant */
tenantName: string;
/** Rol principal del usuario en este tenant */
role: string;
/** Permisos base en este tenant */
permissions: string[];
}
Paso 5: Implementación del Dominio RBAC
// src/lib/rbac/role.ts
/**
* Rol dentro de un tenant específico.
*/
export interface Role {
/** Identificador único del rol */
id: string;
/** ID del tenant al que pertenece este rol */
tenantId: string;
/** Nombre del rol (ej: 'admin', 'manager', 'user') */
name: string;
/** Descripción del rol */
description: string;
/** Permisos incluidos en este rol */
permissions: Permission[];
/** Si es un rol del sistema o personalizado */
isSystemRole: boolean;
/** Si el rol está activo */
isActive: boolean;
/** Fecha de creación */
createdAt: Date;
/** Fecha de última actualización */
updatedAt: Date;
}
// src/lib/rbac/permission.ts
/**
* Permiso simple dentro de un tenant.
*/
export interface Permission {
/** Identificador único del permiso */
id: string;
/** ID del tenant al que pertenece este permiso */
tenantId: string;
/** Nombre del permiso (ej: 'users:read', 'orders:write', 'reports:export') */
name: string;
/** Recurso sobre el que actúa (ej: 'users', 'orders', 'reports') */
resource: string;
/** Acción permitida - puede ser cualquier string (ej: 'read', 'write', 'delete', 'export', 'import', 'approve') */
action: string;
/** Descripción del permiso */
description?: string;
/** Si es un permiso del sistema o personalizado */
isSystemPermission?: boolean;
}
Paso 6: Implementación del Dominio API
// src/lib/api/api-response.ts
/**
* Respuesta estándar de la API.
*/
export interface ApiResponse<T = any> {
/** Datos de respuesta */
data: T;
/** Mensaje informativo */
message?: string;
/** Código de estado HTTP */
statusCode: number;
/** Metadatos adicionales */
meta?: ResponseMetadata;
}
/**
* Metadatos de respuesta.
*/
export interface ResponseMetadata {
/** Timestamp de la respuesta */
timestamp: string;
/** ID de la request para tracking */
requestId: string;
/** Versión de la API */
version: string;
}
// src/lib/api/pagination.ts
/**
* Request de paginación estándar.
*/
export interface PaginationRequest {
/** Página actual (base 1) */
page: number;
/** Elementos por página */
limit: number;
/** Campo para ordenamiento */
sortBy?: string;
/** Dirección del ordenamiento */
sortOrder?: 'asc' | 'desc';
/** Filtros de búsqueda */
filters?: Record<string, any>;
}
/**
* Respuesta paginada estándar.
*/
export interface PaginationResponse<T> {
/** Elementos de la página actual */
items: T[];
/** Información de paginación */
pagination: PaginationInfo;
}
/**
* Información de paginación.
*/
export interface PaginationInfo {
/** Página actual */
currentPage: number;
/** Elementos por página */
itemsPerPage: number;
/** Total de elementos */
totalItems: number;
/** Total de páginas */
totalPages: number;
/** Si hay página anterior */
hasPrevious: boolean;
/** Si hay página siguiente */
hasNext: boolean;
}
Paso 7: Configuración de Exportaciones
// src/lib/index.ts - Exportación principal (barril)
// Tenant domain
export * from './tenant';
// Auth domain
export * from './auth';
// RBAC domain
export * from './rbac';
// UI domain
export * from './ui';
// API domain
export * from './api';
// Common utilities
export * from './common';
// src/lib/tenant/index.ts
export * from './context';
export * from './config';
export * from './permissions';
export * from './features';
export * from './context-info';
// src/lib/auth/index.ts
export * from './user-profile';
export * from './auth-state';
export * from './login-credentials';
export * from './login-result';
export * from './selection-result';
export * from './auth-errors';
Paso 8: Testing y Validación
// src/lib/tenant/context.spec.ts
import { Context } from './context';
describe('Context Interface', () => {
it('should have all required properties', () => {
const context: Context = {
tenantId: 'tenant-123',
tenantName: 'Test Tenant',
apiBaseUrl: 'https://api.test.com',
locale: 'es-ES',
timezone: 'America/Mexico_City',
permissions: {
permissions: [],
modules: {},
resources: {},
},
configuration: {
modules: {},
ui: {
theme: 'default',
branding: {
logo: 'logo.png',
primaryColor: '#000000',
},
},
limits: {
maxUsers: 100,
maxStorage: 1000,
rateLimit: 1000,
maxRoles: 10,
},
},
features: {
advancedReporting: true,
apiAccess: true,
integrations: [],
customBranding: true,
customRoles: true,
},
};
expect(context.tenantId).toBeDefined();
expect(context.tenantName).toBeDefined();
expect(context.apiBaseUrl).toBeDefined();
// ... más validaciones
});
});
Criterios de Éxito
Funcionalidad Core
- ✅ Modelos Completos: Todos los dominios implementados
- ✅ TypeScript Estricto: Sin uso de
any, tipado 100% - ✅ Exportaciones Granulares: Tree shaking optimizado
- ✅ JSDoc Completo: Documentación inline ≥ 95%
Calidad y Testing
- ✅ Type Safety: Validación estricta de tipos
- ✅ Unit Tests: Coverage ≥ 95% de interfaces
- ✅ Integration Tests: Validación con librerías consumidoras
- ✅ Performance: Bundle size < 5KB gzipped
Adopción
- ✅ Migration Guide: Documentación de migración
- ✅ Examples: Ejemplos de uso para cada dominio
- ✅ Backward Compatibility: Versionado semántico
- ✅ CI/CD Integration: Validación automática
Comandos de Desarrollo
# Crear la librería
nx generate @nx/js:library shared-models \
--directory=libs/core \
--importPath=@libs-core/shared-models \
--strict
# Desarrollo
nx serve shared-models --watch
# Testing
nx test shared-models --coverage
nx run shared-models:type-check
# Build y validación
nx build shared-models
nx lint shared-models
# Documentación
nx run shared-models:docs
Migración de Librerías Existentes
Paso 1: Instalar shared-models
// libs/core/security/package.json
{
"dependencies": {
"@libs-core/shared-models": "*"
}
}
Paso 2: Actualizar imports
// Antes
interface Context { ... }
interface UserProfile { ... }
// Después
import { Context, UserProfile } from '@libs-core/shared-models';
Paso 3: Eliminar duplicados
# Eliminar interfaces duplicadas
rm libs/core/security/src/lib/models/context.ts
rm libs/core/security/src/lib/models/user-profile.ts
Esta librería se convierte en la piedra angular del sistema GoGrab, garantizando consistencia de tipos en todo el workspace y facilitando la evolución controlada de los modelos de datos.