Stockear

Un espacio de trabajo de inventario y facturación para pequeñas empresas. Construí esquemas de productos flexibles, herramientas de inventario conversacionales y extracción de documentos de proveedores, junto con facturación electrónica ARCA.

Estas notas históricas de arquitectura describen un diseño FastAPI/Astro y no han sido reconciliadas con el codebase actual en Next.js. Las capturas del producto actual están disponibles en Trabajo seleccionado.

Las tres cosas que hacen único a Stockear

La mayoría de los proyectos de portfolio eligen un dominio. Stockear abarca IA, infraestructura SaaS y cumplimiento regulatorio — simultáneamente.

Interfaz de Chat Inteligente

Hacé preguntas naturales a tu inventario.

En segundo plano, los embeddings (VoyageAI + Google GenAI) potencian la búsqueda semántica sobre tu catálogo. El agente orquesta llamadas a herramientas — CRUD, búsqueda, generación de facturas — en un único turno conversacional.

  • Búsqueda semántica vectorial
  • Orquestación multi-herramienta
  • Groq LLM con llamadas paralelas
  • Respuestas con contexto

SaaS Metering a Escala

Cuotas por tenant sin abstracciones con fugas.

El diseño histórico contempla aislamiento por workspace y tiers de suscripción, con controles de cuotas en la capa de dependencias antes de ejecutar la lógica de negocio en los endpoints que incluyen la dependencia.

  • Aislamiento de esquema por workspace
  • QuotaVerifier inyectado por DI
  • Enforcement por tier de suscripción
  • Seguimiento de uso y log de auditoría

Cumplimiento Fiscal Argentino

Emisión de comprobantes integrada con AFIP.

El diseño histórico de Stockear contempla integración con ARCA/AFIP para facturación electrónica. La arquitectura hexagonal propuesta separa los adaptadores AFIP para permitir pruebas con implementaciones mock.

  • Integración AFIP con arca_arg
  • Aislamiento hexagonal de facturación
  • Adaptador mock para testing
  • Entornos de staging y producción

Vista General de la Arquitectura

Cuatro capas conectadas — cada una con límites claros y responsabilidades definidas.

🎨

Capa Frontend

Construido con Astro 6 + React islands para máximo rendimiento. Shell estático con hidratación selectiva — solo los componentes interactivos envían JavaScript. Lucia Auth maneja la gestión de sesiones con cookies seguras HTTP-only.

Renderizando diagrama…

Decisiones Técnicas

No toda elección es obvia. Estas decisiones arquitectónicas explican el porqué detrás del diseño de Stockear.

ADR-01DDDClean Architecture

Arquitectura Hexagonal en Facturación

Las regulaciones fiscales argentinas (AFIP/ARCA) cambian frecuentemente. El módulo de facturación debe ser testeable sin llamadas reales a la API y debe permanecer desacoplado del framework HTTP.

Decisión

Aplicar el patrón puertos y adaptadores (hexagonal) al dominio de facturación. La lógica de dominio no tiene imports de FastAPI, Motor ni arca_arg.

Justificación

  • La lógica de dominio pura es unit-testeable sin llamar a endpoints de staging de AFIP
  • Intercambio de adaptadores entre mock/staging/producción sin cambiar el código de dominio
  • Los cambios regulatorios quedan aislados en implementaciones de adaptadores, no en reglas centrales
  • Conforme al Principio de Inversión de Dependencias a nivel arquitectónico

Trade-offs

✓Reglas fiscales testeables via adaptadores mock
⚠Más boilerplate de interfaces a mantener
✓Integración AFIP desacoplada — seguro de refactorizar de forma independiente
⚠Sobrecarga conceptual ligeramente mayor para nuevos colaboradores
DDDClean ArchitectureDependency InversionAdapter Pattern
ADR-02Plugin ArchitectureStrategy Pattern

Diseño Agent-First con Tool Registry

La interfaz de chat con IA necesita llamar a múltiples herramientas del backend (CRUD de inventario, búsqueda semántica, generación de facturas). Codificar el dispatch de herramientas de forma rígida crearía acoplamiento fuerte y haría costoso agregar nuevas capacidades.

Decisión

Implementar un Tool Registry donde cada herramienta es un callable auto-descriptivo con un esquema. El agente lee el registry en runtime y enruta las llamadas a herramientas solicitadas por el LLM de forma dinámica.

Justificación

  • Nuevas herramientas se agregan registrándose — cero cambios al código central del agente
  • Los esquemas de herramientas impulsan el function-calling del LLM automáticamente
  • El patrón Registry es naturalmente testeable — las herramientas son solo funciones
  • Habilita ejecución paralela de herramientas para tareas multi-paso del agente

Trade-offs

✓Extensibilidad sin modificar el core
⚠Sobrecarga de tool discovery al inicializar el agente
✓Separación limpia entre orquestación e implementación
⚠Drift de esquema si las firmas de herramientas cambian sin actualizar el registry
Plugin ArchitectureStrategy PatternFunction Calling (LLM)OpenAPI Schema
ADR-03Dependency InjectionCross-Cutting Concerns

Quota Gating por Tenant via Inyección de Dependencias

Cada endpoint de la API debe respetar los límites de suscripción por tenant. Dispersar las verificaciones de cuota en la lógica de negocio llevaría a inconsistencias y bypasses.

Decisión

Inyectar un QuotaVerifier como dependencia FastAPI en cada endpoint protegido. El verificador lee la suscripción del tenant desde MongoDB y lanza HTTP 429 antes de que ejecute la lógica de negocio.

Justificación

  • El enforcement de cuotas es una preocupación transversal — pertenece a DI, no a la lógica de negocio
  • Los nuevos endpoints quedan automáticamente protegidos al incluir la dependencia
  • Tenant-aware: cada workspace tiene contadores de cuota independientes
  • Testeable mediante mock del QuotaVerifier en unit tests

Trade-offs

✓La dependencia compartida centraliza controles de cuota en los endpoints que la incluyen
⚠Lectura extra a MongoDB en cada request protegido
✓Lógica de cuota centralizada — cambiar una vez, aplica en todas partes
⚠La cadena de DI puede ser compleja para dependencias anidadas
Dependency InjectionCross-Cutting ConcernsMiddlewareAOP
ADR-04Event SourcingAppend-Only Log

MongoDB como Event Store para Auditoría

El cumplimiento fiscal argentino requiere un log inmutable de todas las transacciones, cambios de esquema y acciones del agente. El sistema debe ser auditable y reproducible.

Decisión

Usar MongoDB como event store append-only. Todas las acciones significativas (mensajes de chat, emisiones de facturas, cambios de esquema, eventos de cuota) se escriben como documentos de eventos inmutables.

Justificación

  • El modelo de documentos de MongoDB mapea naturalmente a tipos de eventos heterogéneos
  • Diseño de eventos append-only orientado a preservar el registro de auditoría
  • Eventos consultables para informes de cumplimiento sin una DB de auditoría separada
  • La reproducción de eventos permite depurar secuencias del agente post-incidente

Trade-offs

✓Una sola DB para datos operacionales Y auditoría — menor costo de infraestructura
⚠No es un event store especializado (sin características de Kafka/EventStore)
✓Lenguaje de consulta rico para generar informes de cumplimiento
⚠La evolución del esquema de eventos requiere planificación cuidadosa de migraciones
Event SourcingAppend-Only LogCQRSAudit Trail

Arquitectura de Despliegue

Del navegador a la autoridad fiscal — cada capa mapeada.

🌐

User Browser

Astro + React Islands

Shell estático de Astro con hidratación selectiva de React. Cero JS para secciones estáticas.

REST API / HTTPS
▲

Vercel Edge

SSR + Static Assets

Astro desplegado en Vercel. Páginas SSR renderizadas en el edge; assets estáticos con caché global.

HTTP Proxy
⚙️

FastAPI Backend

Python · Agent · Tools

Capa de orquestación principal: agente, tool registry, enforcement de cuotas, lógica de negocio.

MongoDB Wire Protocol
🍃

MongoDB Atlas

Per-Tenant Schemas

Cada workspace recibe un esquema aislado. También actúa como event store para el audit trail.

arca_arg SDK
🧾

AFIP / ARCA

Argentine Tax Authority

Emisión legal de facturas via adaptador hexagonal. Entornos de staging y producción.

Google GenAI API
🧠

AI Embeddings

Google GenAI + VoyageAI

Generación de embeddings para búsqueda semántica. Vectores almacenados en MongoDB para retrieval.