- TypeScript 70%
- JavaScript 19%
- Shell 6.3%
- Python 3.9%
- Go Template 0.6%
| .forgejo/workflows | ||
| .husky | ||
| .opencode | ||
| .specify | ||
| android | ||
| assets | ||
| docs | ||
| specs | ||
| src | ||
| tests | ||
| web | ||
| .gitignore | ||
| .lintstagedrc.json | ||
| .prettierignore | ||
| .prettierrc | ||
| AGENTS.md | ||
| app.config.js | ||
| App.js | ||
| App.js.bak | ||
| app.json | ||
| DOCUMENTACION-COMPLETA.md | ||
| eas.json | ||
| eslint.config.mjs | ||
| index.js | ||
| jest.config.js | ||
| LICENSE | ||
| opencode.json | ||
| package-lock.json | ||
| package.json | ||
| README.md | ||
| screenshot-all.cjs | ||
| screenshot-app.cjs | ||
| test-audit.json | ||
| tsconfig.json | ||
🐝 Cuaderno de Campo Apícola
App móvil offline-first para inspecciones de colmenas por voz.
React Native + Expo. Transcripción local con Whisper. Tres capas de almacenamiento independientes y combinables. Hecha para apicultores de campo, no para gestores de escritorio.
Funciona sola en el móvil. Se integra opcionalmente con SmallCountry y la comunidad apícola.
✨ Principios de diseño
| Principio | Descripción |
|---|---|
| Offline-first absoluto | Sin internet, todo funciona igual. No hay funcionalidad degradada sin cobertura. |
| Una mano, con guantes | Botones grandes, sin precisión táctil fina. |
| Voz como entrada principal | El teclado es el último recurso. |
| Contexto antes que captura | La primera pantalla de una colmena muestra su historial, no un formulario. |
| Datos del usuario, siempre | Nada se envía a ningún sitio sin consentimiento explícito. |
| Sin vendor lock-in | Cualquier backend que implemente el contrato BackendColmenas funciona. |
🏗️ Arquitectura de tres capas
App (React Native + Expo)
│
├── Capa 1: SQLite local (siempre, offline-first)
│
├── Capa 2: farmOS API (cuando hay cobertura)
│ └── farm.corraldelviento.sc
│
└── Capa 3: Servidor comunitario (cuando hay WiFi)
└── Zona Cero → API pública + InvenioRDM
Capa 1 — Standalone (siempre activa)
- SQLite local en el teléfono
- Sin internet, sin cuenta, sin servidor
- Exportación a JSON/CSV
Capa 2 — SmallCountry personal (opcional)
- Sincronización con farmOS vía JSON:API
- OAuth2/OIDC vía Authentik
Capa 3 — Comunidad (opcional, con incentivo)
- Compartir datos anónimos voluntariamente
- Ver datos agregados de la zona a cambio
- Datasets con DOI en InvenioRDM
🧱 Stack técnico
React Native + Expo SDK 56
├── expo-av → grabación de audio
├── react-native-whisper → transcripción local offline
├── expo-sqlite → base de datos local
├── expo-location → GPS
├── expo-camera → fotos (opcional)
├── expo-notifications → alertas locales
├── @tanstack/query → sincronización background
└── expo-updates → OTA desde Forgejo CI
Quality tooling
npm run lint # ESLint (React + React Hooks)
npm run lint:fix # ESLint auto-fix
npm run format # Prettier format all
npm run format:check # Prettier check only
npm test # Jest (core unit tests)
npm run test:watch # Jest watch mode
npm run test:ci # Jest CI mode with coverage
Pre-commit hooks (Husky + lint-staged) enforce formatting and linting automatically.
Parser apícola (voz → datos estructurados)
Sin LLM. Un diccionario especializado es más rápido, más fiable y funciona 100% offline:
const DICCIONARIO_APICOLA = {
reina: {
vista: ['reina presente', 'veo la reina', 'localizada'],
ausente: ['sin reina', 'huérfana', 'no veo reina'],
dudosa: ['reina dudosa', 'no localizo la reina'],
},
varroa: {
ninguna: ['sin varroa', 'varroa cero'],
baja: ['poca varroa', 'varroa baja'],
media: ['varroa media', 'bastante varroa'],
alta: ['mucha varroa', 'varroa crítica'],
},
// ... más términos apícolas
};
🧩 Sistema de plugins (núcleo + módulos)
Toda la funcionalidad de la app se organiza como módulos independientes en src/modules/. El núcleo (src/core/) descubre, carga y coordina estos módulos sin que se importen entre sí.
Arquitectura
src/
├── core/ ← Núcleo (carga módulos, event bus)
│ ├── ModuleRegistry.js ← Registro + resolución de dependencias + lifecycle
│ ├── EventBus.js ← Pub/sub para comunicación entre módulos
│ └── index.js ← API pública (createApp, buildScreenList)
├── modules/ ← Módulos funcionales
│ ├── index.js ← Registro explícito de módulos
│ └── _template/ ← Plantilla documentada para nuevos módulos
Interfaz de un módulo
Cada módulo exporta un objeto con esta forma:
export default {
name: 'mi-modulo', // identificador único (kebab-case)
version: '1.0.0',
displayName: 'Mi Módulo', // nombre legible
description: 'Lo que hace',
requires: ['database'], // módulos que deben cargarse antes
init: async ({ registry, events, services }) => {
// Inicialización: suscribirse a eventos, registrar servicios
return () => {
/* cleanup */
};
},
screens: [
// pantallas para React Navigation
{ name: 'MiScreen', component: MiScreen, options: { title: '...' } },
],
};
Reglas del ecosistema
| Regla | Motivo |
|---|---|
| Sin imports directos entre módulos | Usar events.emit / events.on en lugar de importar otro módulo |
| Sin dependencias circulares | El requires se resuelve con orden topológico — ciclos lanzan error |
init es async |
Cada módulo puede hacer setup asíncrono sin bloquear a otros |
| Pantallas se registran, no se hardcodean | El App.js itera registry.getScreens() para construir el navigator |
| Un módulo = una carpeta | Cada módulo vive en src/modules/<name>/ con su propio index.js |
Cómo crear un módulo nuevo
cp -r src/modules/_template src/modules/mi-modulo
# Editar module.json e index.js
# Añadir import en src/modules/index.js
Luego, el core lo carga automáticamente en el próximo arranque.
🗺️ Hoja de ruta
Fase 1 — MVP de campo (en desarrollo)
| Módulo | Estado |
|---|---|
| Proyecto Expo inicializado | ✅ Desplegado |
Fase 1 — MVP de campo
| Módulo | Estado | Descripción |
|---|---|---|
database |
✅ Desplegado | SQLite local + migraciones (F1.1) |
colmenas |
✅ Desplegado | Lista de colmenas con estado visual (F1.2) |
colmena-detalle |
✅ Desplegado | Detalle colmena: historial, pendientes, alertas (F1.3) |
inspeccion |
✅ Desplegado | Inspección rápida con audio (F1.4) |
whisper |
✅ Desplegado | Transcripción local con Whisper (F1.5) |
parser |
✅ Desplegado | Parser apícola (diccionario determinista) (F1.6) |
exportacion |
✅ Desplegado | Exportación JSON/CSV (F1.7) |
| Arquitectura modular | ✅ Desplegado | ModuleRegistry + EventBus + JSDoc + tests |
| Dashboard General | 📋 Definido | Pendiente de implementación |
Fase 2 — Modo guiado + backends
| Funcionalidad | Estado |
|---|---|
| Árbol de decisión (7 nodos) | 📋 Definido |
| Sincronización Git/Forgejo | 📋 Definido |
| farmOS + Odoo vía CI | 💡 Conceptual |
| Módulo Almacén | 💡 Conceptual |
| Calendario de cría de reinas | 💡 Conceptual |
Fase 3 — Comunidad
| Funcionalidad | Estado |
|---|---|
| Servidor comunitario (FastAPI + PostGIS) | 💡 Conceptual |
| Datasets con DOI | 💡 Conceptual |
| Chat IA (opcional) | 💡 Conceptual |
| Alertas (Schwarmalarm) | 💡 Conceptual |
Leyenda de badges SmallCountry: 💡 Conceptual → 📋 Definido → ✅ Desplegado → 🧪 Validado → ⚔️ Probado
🔧 Desarrollo
# Instalar dependencias
npm install
# Calidad de código
npm run lint # ESLint (src/ + tests/)
npm run lint:fix # ESLint auto-fix
npm run format:check # Prettier check
npm run format # Prettier write
npm test # Jest (50 tests del core)
npm run test:ci # Jest CI con coverage
# Iniciar en web (desarrollo rápido)
npx expo start --web
# Iniciar en Android
npx expo start --android
# Iniciar en iOS
npx expo start --ios
Pre-commit hooks
Husky + lint-staged ejecutan automáticamente ESLint y Prettier sobre los archivos modificados antes de cada commit. Si el lint o el formateo fallan, el commit se rechaza.
Actualizaciones OTA
Los updates se sirven desde Forgejo CI self-hosted. expo-updates apunta a updates.sc.duckdns.org. Sin Expo cloud, sin coste recurrente.
🔗 Integración con SmallCountry
| Servicio | Propósito |
|---|---|
| farmOS | Backend de registros apícolas (Capa 2) |
| Authentik | OAuth2/OIDC |
| Forgejo | Código fuente + CI/CD + OTA updates |
| VictoriaMetrics | Datos de sensores |
| InvenioRDM | Datasets comunitarios con DOI |
| n8n | Middleware de anonimización |
Licencia
Este proyecto está licenciado bajo GNU Affero General Public License v3.0 (AGPLv3) — consulta el archivo LICENSE para más detalles.
Licencia Comercial
SmallCountry ofrece licencias comerciales para empresas u organizaciones que necesiten integrar este software en productos propietarios o que no quieran estar sujetas a los términos de la AGPLv3. Para más información, contacta con SmallCountry.
👥 Proyecto relacionado
- Corral del Viento — Ecosistema apícola de SmallCountry