Files

94 lines
4.4 KiB
TeX

\chapter{Arquitectura bajo prueba}
\label{ch:arquitectura}
\section{C\'omo est\'a dise\~nado el sistema}
IPSExtractor sigue una arquitectura de \textbf{microservicios} detrás de un
\textbf{API Gateway}. El host solo expone el puerto \textbf{8189}; el resto vive
en la red Docker. Los agents Selenium corren en PCs externas (HTTP + PutObject a MinIO).
\noindent\textbf{Nombres:} \texttt{bot-descarga} = orquestador (API); \textbf{agent Selenium} = PC que descarga.
ST-BOT-* mide el orquestador; $\sim$422 fact/h es del agent.
\input{diagrams/arquitectura}
\section{Patrones de dise\~no}
\begin{description}[style=nextline,leftmargin=0.8cm,labelwidth=3.2cm]
\item[API Gateway]
\'Unica puerta p\'ublica. Proxy a extraction, cleaning, count-api y bot-descarga.
Centraliza CORS, health y timeouts (JSON 30\,s; uploads del orquestador 600\,s).
\emph{Implicaci\'on de prueba:} ST-GW-* miden el gateway, no el OCR ni el LLM.
\item[Bounded contexts]
Cada servicio tiene un dominio claro: OCR (count-api), LLM (extraction+workers),
orquestaci\'on de descarga (\texttt{bot-descarga}), limpieza CSV (cleaning).
\emph{Implicaci\'on:} fallos y capacidad se prueban por servicio, no solo E2E.
\item[Cola as\'incrona (ARQ)]
Con \texttt{ASYNC\_QUEUE=true}, el ingest encola en Redis y los workers drenan.
Con \texttt{false} (default), el API procesa en el mismo request (sync).
\emph{Implicaci\'on:} ST-EXT-01 exige async + workers; ST-EXT-02 puede correr sync.
\item[Claim / lease]
Un job \texttt{pending} solo lo toma un agent Selenium (claim at\'omico v\'ia \texttt{bot-descarga}). Heartbeat
mantiene al worker online; sin heartbeat, no se asignan jobs.
\emph{Implicaci\'on:} ST-BOT-01/02 miden el orquestador (heartbeats y contenci\'on de claim).
\end{description}
\input{diagrams/patrones}
\section{Pipeline de negocio}
\input{diagrams/pipeline_negocio}
\begin{enumerate}
\item \textbf{Descarga:} agent Selenium obtiene PDFs $\rightarrow$ MinIO.
\item \textbf{Conteo:} OCR/ONNX valida el documento (filtro de calidad).
\item \textbf{Extracci\'on:} LLM rellena campos $\rightarrow$ PostgreSQL.
\item \textbf{Limpieza:} reglas/CSV sobre el lote.
\end{enumerate}
\section{Inventario de componentes}
\begin{table}[ht]
\centering
\begin{tabular}{@{}llp{5.8cm}@{}}
\toprule
\textbf{Componente} & \textbf{Puerto} & \textbf{Responsabilidad} \\
\midrule
\texttt{api\_gateway} & Host 8189 & Proxy HTTP, health agregado, CORS \\
\texttt{extraction} & 8001 & Tasks, LLM, ingest PDFs \\
\texttt{worker} (ARQ) & --- & Procesamiento async v\'ia Redis \\
\texttt{cleaning} & 8002 & Limpieza CSV / reglas \\
\texttt{count-api} & 8080 & OCR + ONNX, stateless \\
\texttt{bot-descarga} & 8200 & Orquestador: jobs, claim, heartbeats, events \\
PostgreSQL 16 & 5432 & Persistencia compartida \\
Redis 7 & 6379 & Cola ARQ + rate limiter \\
Desktop & local & Cliente Electron/React \\
Agent Selenium & local PC & Descarga PDFs (Selenium/Imaging) + MinIO upload \\
MinIO/S3 & externo & Excel y PDFs del pipeline de descarga \\
\bottomrule
\end{tabular}
\caption{Componentes del sistema bajo prueba.}
\end{table}
\section{Flujo cr\'itico: descarga (orquestador + agent Selenium)}
\input{diagrams/flujo_bot}
Secuencia resumida:
\begin{enumerate}
\item Agent Selenium: \texttt{register} + loop \texttt{heartbeat} / \texttt{claim\_pending} ($\sim$8\,s).
\item Desktop: \texttt{POST /bot-descarga/jobs} (Excel, \texttt{worker\_id}, \texttt{job\_id}).
\item API: valida job padre y worker online; sube Excel a MinIO; estado \texttt{pending}.
\item Agent Selenium: claim $\rightarrow$ \texttt{RUNNING}; descarga Excel; Selenium/Imaging; PutObject PDFs.
\item Eventos \texttt{POST /events}; cierre \texttt{PATCH /jobs/\{id\}} (\texttt{completed}/\texttt{failed}).
\end{enumerate}
Layout MinIO:
\begin{lstlisting}[language={},caption={Prefijos MinIO del pipeline de descarga}]
uploads/{download_job_id}/input.xlsx
downloads/{download_job_id}/{nit}/{radicado}.pdf
downloads/{download_job_id}/_manifest.json
\end{lstlisting}
\section{Otros flujos de negocio}
\begin{description}
\item[Conteo] Desktop $\rightarrow$ \texttt{POST /count/v1/count} $\rightarrow$ \texttt{POST /count-jobs} $\rightarrow$ validaci\'on humana.
\item[Extracci\'on] \texttt{from-count} o ingest de PDFs $\rightarrow$ (ARQ) workers $\rightarrow$ filas en BD.
\item[Limpieza] Job cleaning desde \texttt{extraction\_batch\_id} o CSV upload.
\end{description}