La decision arquitectonica de Admin Finance se centra en maximizar la reutilizacion de codigo entre plataformas. El resultado es un proyecto donde el 100% del codigo de dominio y datos es compartido entre Android y Desktop, con solo la capa de presentacion y la inyeccion de dependencias siendo especificas de cada plataforma.
Estructura de Directorios
composeApp/
├── src/commonMain/kotlin/com/masbits/studio/
│ ├── presentation/ # UI (Composables, ViewModels) [COMUN]
│ ├── domain/ # Models, Use Cases [COMUN]
│ ├── data/ # Repositories, Database, Sync [COMUN]
│ ├── di/ # Koin modules [PARCIALMENTE COMUN]
│ └── utils/ # Helpers [COMUN]
├── src/androidMain/kotlin/ # Android-specific [ANDROID]
│ ├── MainActivity.kt
│ └── di/
│ ├── AndroidDI.kt
│ └── PresentationModule.kt
└── src/jvmMain/kotlin/ # Desktop-specific [DESKTOP]
├── main.kt
└── di/
├── DesktopDI.kt
└── PresentationModule.ktCapa de Dominio
La capa de dominio contiene todos los modelos de dominio y la logica de negocio pura, sin dependencias de plataforma:
- Transaction — Modelo principal con tipo (INCOME, EXPENSE, TRANSFER), categoria, monto, fecha y opcionales empresa y notas
- Company — Gestion de multiples empresas para multi-tenancy
- ExpenseCategory — Categorias de gastos con colores para visualizacion
- Invoice / VATEntry — Documentos para exportacion de IVA
- DailyHourSettings — Configuracion de horas diarias trabajadas
Los modelos utilizan serializacion Kotlin para la sincronizacion P2P y son completamente independientes de la plataforma subyacente.
Capa de Datos
La capa de datos implementa el Repository Pattern, abstraendo completamente el almacenamiento subyacente:
SQLDelight como Fuente de Verdad
SQLDelight genera tipos de datos a partir de archivos .sq definidos por el desarrollador. Esto proporciona:
- Tipos de datos compilados y seguros desde la base de datos
- Migrationes versionadas y validadas en compilacion
- Queries tipadas sin riesgo de errores de string
Repositorios Implementados
- TransactionRepository — CRUD completo, filtrado por fecha, calculo de totales por tipo
- VATRepository — Gestion de facturas y entradas de IVA
- DeductionRepository — Deducciones fiscales por empresa
- DailyHourSettingsRepository — Preferencias de horas diarias
- PreferencesManager — Preferencias generales de la app (tema, configuracion)
Sincronizacion P2P
El sistema de sincronizacion se implementa como una capa de datos adicional:
- SyncService — Orquestador principal que gestiona la conexion, deteccion de dispositivos y ejecucion de sincronizaciones
- SyncProtocol — Protocolo personalizado de comunicacion basado en TCP
- SyncMessage — Tipos de mensajes: DISCOVER, DISCOVER_ACK, SYNC_REQUEST, SYNC_DATA, SYNC_ACK, ERROR, CLOSE
- SyncMerger — Algoritmo de fusion basado en timestamps para resolver conflictos en campos modificados de transacciones
Capa de Presentacion
La presentacion utiliza Jetpack Compose con arquitectura MVVM:
- ViewModels — TransactionViewModel, CompanyViewModel, SettingsViewModel, etc.
- StateFlow — Estado reactivo con estados de carga, error y datos
- Composables — Componentes reutilizables organizados por dominio: charts, transactions, companies, export, settings
Aunque la mayor parte de los Composables esta en commonMain, algunos componentes especificos de plataforma (como la actividad principal en Android o el window en Desktop) requieren implementaciones separate.
Inyeccion de Dependencias con Koin
Koin gestiona todo el ciclo de vida de las dependencias:
DataModule (commonMain)
Define todas las dependencias de la capa de datos y dominio:
// Database
single { AppDatabase(driver = SqlDriver(...)) }
single { TransactionRepositoryImpl(database = get()) }
single { VATRepositoryImpl(database = get()) }
// ... mas repositorios// Sync
single { SyncService(...) }
single { SyncMerger(...) }
PresentationModule (platform-specific)
Define los ViewModels y la inicializacion de Koin por plataforma:
// androidMain - AndroidDI.kt
class AndroidDI : KoinAndroidContext { ... }
// jvmMain - DesktopDI.kt
fun startDesktopDI() { startKoin { ... } }Diagrama de Dependencias
┌─────────────┐ ┌─────────────┐
│ Presentation │────▶│ Domain │
│ (Compose) │ │ (Models) │
└──────┬──────┘ └──────┬──────┘
│ │
▼ ▼
┌─────────────┐ ┌─────────────┐
│ Koin DI │────▶│ Data │
│ (Koin) │ │ (SQLDelight│
└─────────────┘ │ + TCP Sync)│
└─────────────┘Testing
El proyecto incluye 86+ tests en commonTest que se ejecutan tanto en Android como en Desktop:
- MockK — Mocking de dependencias en tests
- Turbine — Testing de Flows/StateFlow
- SQLDelight JDBC Driver — Driver SQLite JDBC para tests en JVM
Resultados de la Arquitectura
- Ratio de codigo compartido: 100% en capa de dominio y datos
- Build dual: APK Android (~13MB) + ejecutable Windows MSI/Portable
- Testing unificado — Los mismos tests ejecutables en ambos targets
- Escalabilidad — Nuevas plataformas (iOS, Web) podrian agregar codigo sin modificar el comun