Herramientas de usuario

Herramientas del sitio


ada:howto:sicoferp:factory:new-migracion-sicoferp:module-interactions

Interacción de módulos y flujos de integración

Grafo de dependencias

┌─────────────────────────────────────────────────────────────────┐
│                  Capa de Presentación (UI)                      │
│         Machine (app)     |     RutaPAE (app)                   │
└────────────┬──────────────────────────┬──────────────────────────┘
             │                          │
             ▼                          ▼
┌──────────────────────────┐  ┌─────────────────────────┐
│  MachineDomain (Logic)   │  │  RutaPAEDomain (Logic)  │
│ - StateManager           │  │ - P2PManager            │
│ - P2PManager             │  │ - DomainManager         │
│ - SyncServices           │  │ - SyncServices          │
└────────┬─────────────────┘  └────────┬────────────────┘
         │                             │
         ▼                             ▼
┌──────────────────────────┐  ┌─────────────────────────┐
│   MachineData (DB)       │  │   RutaPAEData (DB)      │
│ - Repository             │  │ - Repository            │
│ - Services               │  │ - Services              │
└────────┬─────────────────┘  └────────┬────────────────┘
         │                             │
         └──────────────┬──────────────┘
                        ▼
        ┌────────────────────────────────────┐
        │   VectorialDB (ORM)                │
        │   - Table<T>                       │
        │   - Índices vectoriales            │
        │   - SQLite backend                 │
        └────────────────────────────────────┘
                        │
                        ▼
                    ┌────────────┐
                    │  DB.sqlite │
                    └────────────┘

              Comunicación inter-app
              
┌──────────────────────────────────┐  ┌──────────────────────────┐
│  Machine (REST Server)           │  │  RutaPAE (REST Client)   │
│  directlink:8000/p2p/...         │  │  Conecta a Machine P2P   │
└────────────┬─────────────────────┘  └──────────┬───────────────┘
             │                                    │
             └────────────┬───────────────────────┘
                          ▼
              DirectLink (Wi-Fi Direct)
              Hotspot (tethering)
              
┌──────────────────────────────────────────────────────────────┐
│  Servicios compartidos                                       │
│  Contract - modelos P2P                                      │
│  Core - logging e interfaces                                │
│  ComputerVision - modelos IA                                │
└──────────────────────────────────────────────────────────────┘

Ciclo de vida del estado de entrega

Máquina (Machine)

Usuario inicia            StateManager crea            Ejecuta transiciones
captura de entrega        StateWorkflow
       │                          │                           │
       ▼                          ▼                           ▼
LaboratoryScreen        StateManager.init()        WaitingForWeight
       │                          │                    │
       └──────────┬───────────────┘                    ├─→ CaptureImages
              UI espera                                 ├─→ CaptureFace
         cambios de estado                             ├─→ ComparingWeights
              │                                        ├─→ GenerateEmbedding
              ▼                                        ├─→ VerifyInDatabase
      StateNameEmitter                                 ├─→ SaveDelivery
         emite evento                                  └─→ WaitForWeightRemoved
              │
              ▼
         Flow<String>
              │
              ▼
         UI Composable
     actualiza según nombre

Sincronización P2P: RutaPAE → Machine

Fase 1: Descubrimiento

RutaPAE                     DirectLink              Machine
(cliente)                   (P2P)                   (servidor)
   │                           │                         │
   ├─ discoverableMachineIds() ├─────────────────────────┤
   │                           │    broadcast peers      │
   │◄──────────────────────────┤◄────────────────────────┤
   │      SET<P2PPeer>         │
   │
   ├─ discoveredMachineCandidates()
   │  (devuelve peers activos)
   │

Fase 2: Conexión

RutaPAE                     DirectLink              Machine
(cliente)                   (P2P)                   (servidor)
   │                           │                         │
   ├─ connectMachine(id)        ├─────────────────────────┤
   │                           │  negotiate connection   │
   │                           ├─────────────────────────►│
   │                           │                         │
   │                           ◄─────────────────────────┤
   │                           │  accept / reject        │
   │◄───────────────────────────┤                         │
   │    connection ready        │                         │
   │

Fase 3: Sincronización de entregas

RutaPAE             DirectLink          Machine
(cliente)           (HTTP)              (servidor)
   │                   │                    │
   ├─ syncDeliveries   ├─────────────────────┤
   │                   │                    │
   │    GET /p2p/      │                    │
   │    machine/       │                    │
   │    deliveries/1/1 ├──────────────────►│
   │                   │                    │
   │                   │   query db.sqlite  │
   │                   │   Delivery.all()   │
   │                   │                    │
   │                   ◄──────────────────┤
   │                   │                    │
   │    LIST[          │  P2PDeliveriesPageResponse
   │      P2PDelivery  │  - results: LIST[P2PDelivery]
   │    ]              │  - totalCount
   │◄───────────────────┤  - pageIndex
   │                   │
   ├─ DeliveryService  │
   │   create(list)    │
   │                   │
   ├─ persist in DB    │
   │  RutaPAEData      │
   │
   └─ UI updates

Flujo completo de entrega: Machine

STEP 1: Presentación         STEP 2: Dominio            STEP 3: Datos
(Machine UI)                 (MachineDomain)            (MachineData)

User clicks "Capture"
         │
         ▼
LaboratoryScreenUI
    ├─ VM.startCapture()
    │        │
    │        ▼
    │   StateManager.init()
    │        │
    │        ▼
    │   Loop: for state in workflow
    │        │
    │        ├─→ WaitingForWeight.run()
    │        │        │
    │        │        ├─ await scale input
    │        │        │  [Hardware interface]
    │        │        │
    │        │        ├─ next() ──────────┐
    │        │        │                   ▼
    │        │        │            CaptureImages.run()
    │        │        │                   │
    │        │        │                   ├─ Camera2 capture
    │        │        │                   │  [Hardware interface]
    │        │        │                   │
    │        │        │                   ├─ next()
    │        │        │                   │        ▼
    │        │        │                CaptureFace.run()
    │        │        │                   │
    │        │        │                   └─ next() ─────┐
    │        │        │                                  ▼
    │        │        │                  GenerateEmbedding.run()
    │        │        │                         │
    │        │        │                         ├─ ComputerVision
    │        │        │                         │  .generateEmbedding()
    │        │        │                         │
    │        │        │                         ├─ next()
    │        │        │                         │        ▼
    │        │        │              VerifyInDatabase.run()
    │        │        │                         │
    │        │        │    ┌────────────────────┘
    │        │        │    │
    │        │        │    ▼ (acceso a DB)
    │        │        │  BeneficiaryService.findSimilar()
    │        │        │    │
    │        │        │    ├─ VectorDB nearest neighbors
    │        │        │    │  query: embedding, k=5
    │        │        │    │
    │        │        │    ▼
    │        │        │  Beneficiary[]
    │        │        │    │
    │        │        │    ▼ (regresa a estado)
    │        │        │  state.next() ────┐
    │        │        │                   ▼
    │        │        │            SaveDelivery.run()
    │        │        │                   │
    │        │        │                   ├─ DeliveryService.save()
    │        │        │                   │    │
    │        │        │                   │    ├─ Repository.create()
    │        │        │                   │    │
    │        │        │                   │    ▼
    │        │        │                   │  DB INSERT
    │        │        │                   │    │
    │        │        │                   └──┬─┘
    │        │        │
    │        │        ├─ StateNameEmitter.emit() ────┐
    │        │        │                              │
    │        ◄─────────┤                              │
    │  StateNameEmitter                               │
    │  observable                                     │
    │        │                                        │
    │        └──────────────────────────────────────┐│
    │                                               ││
    ▼                                               ▼▼
LaunchedEffect in Composable
  .collect { stateName: String ->
    // updateUI(stateName)
  }

Manejo de errores y reintentos

State.run(next, retry)
         │
         ├─ try {
         │       action()
         │       next()  ──────► continuar a siguiente estado
         │  }
         │
         └─ catch (e) {
                retry(reason)  ──────► retroceder a estado anterior
           }

Ejemplo: CaptureFace falla
         │
         ▼
    retry("Camera error")
         │
         ▼
    estado anterior reactiva
         │
         ▼
    usuario intenta nuevamente

Inyección de dependencias

Machine (Dagger/Hilt)

Activity
  ├─ ViewModelFactory (Hilt)
  │    ├─ ViewModel
  │    │    ├─ StateManager
  │    │    ├─ Repository
  │    │    └─ Hardware
  │    │
  │    ├─ StateManager
  │    │    ├─ Repository
  │    │    ├─ Camera2Service
  │    │    ├─ ScaleManager
  │    │    └─ ComputerVision
  │    │
  │    └─ Repository
  │         ├─ DeliveryService
  │         ├─ BeneficiaryService
  │         └─ VectorDB

RutaPAE (inyección manual)

Worker (enqueue)
  ├─ DomainManager.init()
  │    ├─ P2PManager
  │    │    ├─ DirectLink
  │    │    └─ Contract models
  │    │
  │    └─ Repository
  │         ├─ DeliveryService
  │         └─ MachineService
  │
  └─ DomainManager.p2pManager  ────► syncDeliveriesFromMachine()

Comunicación de eventos

Machine: StateFlow

StateManager
     │
     ├─ StateNameEmitter ──► Flow<String>
     │       │
     │       └─ emit("CapturingFace")
     │
     ├─ StateMessageEmitter ──► Flow<String>
     │       │
     │       └─ emit("Por favor espere...")
     │
     └─ SyncRunningEmitter ──► Flow<Boolean>
             │
             └─ emit(true) cuando sincronización activa

Observadores:
     │
     ├─ LaboratoryScreenUI.stateCollector()
     ├─ ProgressBarUI.messageCollector()
     └─ StatusIndicatorUI.syncCollector()

RutaPAE: Emisores

DeliverySyncWorker
     │
     ├─ DeliverySyncUiEmitter
     │       │
     │       └─ emit(SyncDeliveriesResult)
     │
     └─ SyncRunningEmitter
             │
             └─ emit(true) durante sync

Observadores:
     │
     ├─ MachineListScreenUI
     └─ SyncProgressIndicatorUI

Casos de uso críticos

Caso 1: Máquina recibe beneficiario nuevo (HTTP)

Backend notifica                  Machine descarga              Machine guarda
nueva beneficiaria        
       │                                   │                           │
       ▼                                   ▼                           ▼
Backend                     MachineEndpoints.getBeneficiaries()    BeneficiaryService.create()
                                   │                                   │
                                   ├─ FuelHttpClient.get()             ├─ Repository.create()
                                   │                                   │
                                   ├─ parse JSON                       ├─ VectorDB add()
                                   │                                   │
                                   └─ MachineData.Repository           └─ DB.sqlite INSERT

Caso 2: Máquina y RutaPAE se sincronización (P2P)

RutaPAE inicia             Machine responde              RutaPAE persiste
sincronización             con entregas
       │                           │                           │
       ▼                           ▼                           ▼
RutaPAEUI                   Machine P2P server           RutaPAEData.Repository
  ├─ enqueue Worker              │                           │
  │                              ├─ query Delivery DB         ├─ DeliveryService.create()
  │                              │                           │
  └──► Worker starts             ├─ serialize                └─ persist
         │                       │                               │
         ├─ init Domain          └─ HTTP response               ▼
         │                           │                       DB.sqlite
         ├─ P2PManager.connect()     │
         │                           │
         ├─ P2PManager.sync()────────┤
         │                          
         └─ Worker.done()

Caso 3: Error durante captura (Machine)

CaptureFace.run()
       │
       ├─ try {
       │     Camera.takePhoto()
       │  } ──── EXCEPCIÓN
       │
       └─ catch {
             retry("Camera no disponible")
         }
             │
             ▼
         retrocede a CaptureImages
             │
             ▼
         estado anterior = true
             │
             ▼
         UI muestra botón "Reintentar"
             │
             ▼
         usuario presiona "Reintentar"
             │
             ▼
         vuelve a intentar CaptureFace

Optimizaciones de concurrencia

Coroutines en Machine

StateManager.cycle()
       │
       └─ suspend fun (en LaunchedEffect)
              │
              ├─ state.run() ──► suspender si no hay input
              │
              └─ observable emitters ──► no bloquea UI

Coroutines en RutaPAE

DeliverySyncWorker
       │
       └─ suspend fun syncDeliveriesFromMachine()
              │
              ├─ delay espera entre reintentos
              │
              └─ parallel requests via coroutines

Versioning y compatibilidad

Machine v0.9.0             RutaPAE v0.4.0
     │                            │
     ├─ uses Contract v...        ├─ uses Contract v...
     │                            │
     ├─ uses DirectLink v...      ├─ uses DirectLink v...
     │                            │
     └─ API mínima: SDK 27        └─ API mínima: SDK 27
        API objetivo: SDK 36         API objetivo: SDK 36
ada/howto/sicoferp/factory/new-migracion-sicoferp/module-interactions.txt · Última modificación: 2026/04/07 20:00 por 10.1.62.149