Arquitectura
Personal Comander es una app Android offline-first: el estado de sala (mesas, carta, comandas) vive en Room. Identity es la fuente de verdad de la cuenta del camarero y de las membresías; SesionStore y Room actúan como cache/fallback. Las otras conexiones de red son el cliente TPV (LAN), Bar LAN (turno) y (opcionalmente) el reconocimiento de voz del sistema.
Stack
| Capa | Tecnología |
|---|---|
| UI | Jetpack Compose + Material 3 |
| Navegación | androidx.navigation.compose |
| Estado | ViewModel + StateFlow |
| Base de datos | Room (SQLite) con KSP |
| Serialización | Gson (sync TPV, backup JSON) |
| Voz | Android SpeechRecognizer (on-device) |
| DI | Manual (Application cast vía viewModel factory) |
| Build | Gradle KTS + Version Catalog |
| Desugaring | desugar_jdk_libs (Java 11 → API 24) |
Estructura del proyecto
app/src/main/java/com/jaminsmoke/personalcomander/
├── MainActivity.kt # Entry point, edge-to-edge, theme
├── PersonalComanderApp.kt # DB init, seed, Room builder
├── data/
│ ├── Entities.kt # Mesa, Producto, Pedido, LineaPedido + enums
│ ├── Daos.kt # Room DAOs + @Transaction ops
│ ├── AppDatabase.kt # Room DB, migraciones, repos
│ ├── Seed.kt # First-launch seed
│ ├── BackupJson.kt # JSON import/export models
│ ├── Tpv.kt / TpvCliente.kt # POS sync adapters
│ ├── CategoriaIcono.kt # Category → emoji mapping
│ └── ...
└── ui/
├── PersonalComanderApp.kt # NavHost (home, mesas, gestión, ajustes, auth, perfil, comanda/{id})
├── HomeScreen.kt / HomeViewModel.kt
├── MesasScreen.kt / MesasViewModel.kt / MesasBoard.kt # Board + list views
├── ComandaScreen.kt / ComandaViewModel.kt # Order taking
├── AjustesScreen.kt / AjustesAcceso.kt / AjustesViewModel.kt # Hub Ajustes (TPV, Copias)
├── gestion/ # Hub Gestión (Carta, Locales, Invitaciones)
├── sesion/ # Auth, perfil, QR y visibilidad
├── Voz.kt / VozParser.kt # Voice recognition + NL parser
├── Formato.kt # Double.formatoEuro() extension
└── theme/ # Color.kt, Theme.kt, Type.kt
Flujo de datos
UI (Compose) → ViewModel (StateFlow) → Repository → Room (SQLite)
↑ ↓
VozParser (NLP) Sync TPV (Gson/LAN)
Backup JSON (import/export)
Identity / Personal Bar (v1.6)
- Los ViewModels exponen
StateFlowque la UI consume concollectAsState(). - Las operaciones que tocan 2+ tablas usan
@Transactionodb.withTransaction {}. - El catálogo TPV se importa como JSON sobre TCP en la red local y se inserta con
replace. - La identidad del camarero se registra en Identity (servicio camareros en el VPS, HTTPS). El modo Local conserva el funcionamiento offline; la sesión se cachea si Identity no responde.
- Las membresías de establecimiento las sirve Identity (
GET /v1/camareros/me/establecimientos); Bar consulta Identity. Ligar el turno sigue siendo Bar LAN. El radar de Resumen oye el beacon UDP 8788 de Bar y confirma conGET /health(el host no se pinta). - En modo Establecimiento, una comanda enviada conserva primero el estado local y después intenta publicar una ronda a Personal Bar.
Voz
El reconocimiento y el parser NLP viven en Voz.kt / VozParser.kt. Timeouts, Bluetooth y matching están documentados en Voz.
Migraciones y schema
- El schema de Room se exporta a
app/schemas/(KSProom.schemaLocation). - Cada cambio de entidad requiere una migración numerada + test de migración en
androidTest(ver Modelo de datos).