semillero-INVIMA/diagramas/frontend-clases.mmd

349 lines
8.5 KiB
Plaintext

classDiagram
class App{
}
class AuthUser {
<<type>>
+id: string | number
+username: string
+fullName: string
+role: string
}
class AuthSession {
<<type>>
+user: AuthUser
+accessToken: string
+expiresAt: string
}
class ApiEnvelope~T~ {
<<type>>
+ok: boolean
+data: T
}
class InvimaDataset {
<<type>>
+key: string
+id: string
+name: string
+defaultCategory: string
}
class InvimaCategory {
<<type>>
+categoria: string
+slug: string
+total: number
}
class InvimaFilterOption {
<<type>>
+value: string
+total: number
}
class InvimaCatalogItem {
<<type>>
+source_dataset_key: string
+source_dataset_id: string
+source_dataset_name: string
+categoria_linea: string
+categoria_canonica: string
+categoria_slug: string
+expediente?: string
+registro_sanitario?: string
+producto?: string
+titular?: string
+estado_registro?: string
+fecha_expedicion?: string
+fecha_vencimiento?: string
+modalidad?: string
+grupo?: string
+marca?: string
+principio_activo?: string
+forma_farmaceutica?: string
+presentacion_comercial?: string
+atc?: string
+rol_nombre?: string
+rol_tipo?: string
+ciudad_titular?: string
+pais_titular?: string
+fabricante?: string
+importador?: string
+vigencia?: string
+score?: number
}
class InvimaCatalogResponse {
<<type>>
+items: InvimaCatalogItem[]
+total: number
+limit: number
+offset: number
}
class InvimaFiltersResponse {
<<type>>
+estados: InvimaFilterOption[]
+modalidades: InvimaFilterOption[]
+grupos: InvimaFilterOption[]
}
class InvimaSyncSummary {
<<type>>
+datasets: number
+fetched: number
+persisted: number
+pages: number
+failed?: number
+requested?: number
}
class InvimaSyncResponse {
<<type>>
+ok: boolean
+alreadyRunning?: boolean
+job?: InvimaSyncJob | null
+summary?: InvimaSyncSummary
+failed?: #123; datasetKey: string; error: string; #125;[]
}
class InvimaSyncJobDataset {
<<type>>
+key: string
+datasetKey: string
+datasetId: string | null
+name: string
+status: "pending" | "running" | "completed" | "failed"
+fetched: number
+persisted: number
+pages: number
+warnings: string[]
+error: string | null
+startedAt: string | null
+updatedAt: string
+finishedAt: string | null
}
class InvimaSyncJob {
<<type>>
+id: string
+status: "running" | "completed" | "failed"
+requested: number
+completed: number
+failed: number
+fetched: number
+persisted: number
+pages: number
+concurrency?: number
+pageSize?: number
+datasets: InvimaSyncJobDataset[]
+summary?: InvimaSyncSummary | null
+error?: string | null
+startedAt: string
+updatedAt: string
+finishedAt: string | null
}
class InvimaSyncDatasetStats {
<<type>>
+key: string
+id: string
+name: string
+localRows: number
+selected: boolean
}
class InvimaSyncStats {
<<type>>
+at: string
+totals: #123; catalogRows: number; rawRows: number; categories: number; datasetsWithData: number; vigentes: number; vencidos: number; maxUpdatedAt: string | null; #125;
+datasets: InvimaSyncDatasetStats[]
}
AuthSession -- AuthUser
InvimaCatalogResponse -- "0..*" InvimaCatalogItem
InvimaFiltersResponse -- "0..*" InvimaFilterOption
InvimaFiltersResponse -- "0..*" InvimaFilterOption
InvimaFiltersResponse -- "0..*" InvimaFilterOption
InvimaSyncResponse -- InvimaSyncJob
InvimaSyncResponse -- InvimaSyncSummary
InvimaSyncJob -- "0..*" InvimaSyncJobDataset
InvimaSyncJob -- InvimaSyncSummary
InvimaSyncStats -- "0..*" InvimaSyncDatasetStats
class AuthService{
-apiBase: "/api/auth"
-_token: WritableSignal~string | null~
-_user: WritableSignal~AuthUser | null~
+user: Signal~AuthUser | null~
+isAuthenticated: Signal~boolean~
-http: HttpClient
-hydrate() void
-setSession() void
+clearSession() void
+getAccessToken() string | null
+login() Observable~AuthSession~
+me() Observable~AuthUser~
+logout() Observable~boolean~
}
class InvimaService{
-apiBase: "/api/invima"
-http: HttpClient
-buildExportParams() HttpParams
-buildFallbackFilename() string
-extractFilename() string
+getDatasets() Observable~#123; items: InvimaDataset[]; #125;~
+getCategories() Observable~#123; items: InvimaCategory[]; #125;~
+getFilterOptions() Observable~InvimaFiltersResponse~
+searchCatalog() Observable~InvimaCatalogResponse~
+sync() Observable~InvimaSyncResponse~
+getSyncStats() Observable~InvimaSyncStats~
+getSyncJob() Observable~#123; ok: boolean; job: InvimaSyncJob | null; #125;~
+exportCatalog() Observable~InvimaExportFile~
+buildExportUrl() string
}
class CatalogQuery {
<<type>>
+q?: string
+categorias?: string[]
+datasets?: string[]
+estados?: string[]
+modalidades?: string[]
+grupos?: string[]
+fechaVencDesde?: string
+fechaVencHasta?: string
+fechaExpDesde?: string
+fechaExpHasta?: string
+onlyVigentes?: boolean
+limit?: number
+offset?: number
}
class InvimaExportFile {
<<type>>
+blob: Blob
+filename: string
+contentType: string
}
class LoginPageComponent{
-auth: AuthService
-router: Router
-route: ActivatedRoute
+loading: WritableSignal~boolean~
+error: WritableSignal~string~
+identifier: string
+password: string
+submit() void
}
LoginPageComponent -- AuthService
class DashboardPageComponent{
-auth: AuthService
+fullName: Signal~string~
}
DashboardPageComponent -- AuthService
class CatalogPageComponent{
-invima: InvimaService
+loading: WritableSignal~boolean~
+error: WritableSignal~string~
+exporting: WritableSignal~"csv" | "xlsx" | null~
+exportMessage: WritableSignal~string~
+exportError: WritableSignal~string~
+items: WritableSignal~InvimaCatalogItem[]~
+total: WritableSignal~number~
+categories: WritableSignal~InvimaCategory[]~
+datasets: WritableSignal~InvimaDataset[]~
+estados: WritableSignal~InvimaFilterOption[]~
+modalidades: WritableSignal~InvimaFilterOption[]~
+grupos: WritableSignal~InvimaFilterOption[]~
+selectedCategories: WritableSignal~string[]~
+selectedDatasets: WritableSignal~string[]~
+limit: WritableSignal~number~
+offset: WritableSignal~number~
+page: Signal~number~
+hasMore: Signal~boolean~
+qText: string
+estado: string
+modalidad: string
+grupo: string
+fechaVencDesde: string
+fechaVencHasta: string
+fechaExpDesde: string
+fechaExpHasta: string
+onlyVigentes: boolean
-buildQuery() CatalogQuery
-loadMetadata() void
-loadData() void
+applyFilters() void
+clearFilters() void
+toggleCategory() void
+isCategorySelected() boolean
+toggleDataset() void
+isDatasetSelected() boolean
+changeLimit() void
+nextPage() void
+prevPage() void
+download() void
+formatDate() string
+isVigente() boolean
+isVencido() boolean
}
CatalogPageComponent -- InvimaService
class SyncPageComponent{
-invima: InvimaService
-refreshMs: 10000
-refreshHandle: number | null
-announcedFinalJobId: string | null
+loading: WritableSignal~boolean~
+message: WritableSignal~string~
+statsError: WritableSignal~string~
+jobError: WritableSignal~string~
+datasets: WritableSignal~InvimaDataset[]~
+selected: WritableSignal~string[]~
+stats: WritableSignal~InvimaSyncStats | null~
+job: WritableSignal~InvimaSyncJob | null~
+baselineTotal: WritableSignal~number | null~
+baselineByDataset: WritableSignal~Record~string, number~~
+liveAdded: Signal~number~
+pageSize: number
+concurrency: number
+ngOnDestroy() void
-loadStats() void
-loadJob() void
-ensureBaseline() void
-refreshLiveMessage() void
-buildFinalMessage() string
-captureBaselineFromCurrentStats() void
+datasetDelta() number
+formatNumber() string
+formatDateTime() string
+toggle() void
+isSelected() boolean
+selectAll() void
+sync() void
}
OnDestroy<|..SyncPageComponent
SyncPageComponent -- InvimaService
class MainLayoutComponent{
+auth: AuthService
-router: Router
+menu: MenuItem[]
+initials: Signal~string~
+logout() void
}
class MenuItem {
<<type>>
+label: string
+path: string
+hint: string
}
MainLayoutComponent -- AuthService
MainLayoutComponent -- "0..*" MenuItem