App móvil Cuaderno de Campo Apícola — React Native + Expo
  • TypeScript 70%
  • JavaScript 19%
  • Shell 6.3%
  • Python 3.9%
  • Go Template 0.6%
Find a file
tonatiuh c7afb24330
Some checks failed
Build & Test (cuaderno-apicola-app) / build-apk (push) Has been cancelled
Build & Test (cuaderno-apicola-app) / quality-gate (push) Has been cancelled
chore: update .opencode infrastructure files
2026-05-31 14:58:09 +02:00
.forgejo/workflows fix(ci): arreglar --legacy-peer-deps y testPathPatterns en workflows 2026-05-31 14:15:47 +02:00
.husky feat(workflow): pre-push gate, CI build-and-test, fast iteration docs 2026-05-31 13:23:09 +02:00
.opencode chore: update .opencode infrastructure files 2026-05-31 14:57:31 +02:00
.specify docs: añadir specs 009-018 (voz, tutor, protocolos, calendario, ajustes, antifragil, recetas, analisis, cria, meteorologia) 2026-05-29 22:58:19 +02:00
android build(android): force arm64-v8a only via splits.abi 2026-05-31 11:11:04 +02:00
assets Initial commit: proyecto Expo + README 2026-05-29 14:12:48 +02:00
docs feat(workflow): pre-push gate, CI build-and-test, fast iteration docs 2026-05-31 13:23:09 +02:00
specs fix(auditoria): corregir audio compat layer, navegacion colmenas:selected, FloatingMicButton, migrar voice a expo-speech-recognition 2026-05-31 13:56:12 +02:00
src style: format after audit fixes 2026-05-31 13:56:45 +02:00
tests style: format all files with Prettier 2026-05-31 13:26:46 +02:00
web style: format all files with Prettier 2026-05-31 13:26:46 +02:00
.gitignore chore: gitignore para mockups y APKs 2026-05-31 09:10:23 +02:00
.lintstagedrc.json chore(infra): configurar ESLint, Prettier, Husky, JSDoc y tests del core 2026-05-29 18:33:28 +02:00
.prettierignore chore(infra): configurar ESLint, Prettier, Husky, JSDoc y tests del core 2026-05-29 18:33:28 +02:00
.prettierrc chore(infra): configurar ESLint, Prettier, Husky, JSDoc y tests del core 2026-05-29 18:33:28 +02:00
AGENTS.md docs: añadir specs 009-018 (voz, tutor, protocolos, calendario, ajustes, antifragil, recetas, analisis, cria, meteorologia) 2026-05-29 22:58:19 +02:00
app.config.js fix: eliminar updates del manifest via app.config.js 2026-05-30 18:31:55 +02:00
App.js fix(auditoria): corregir audio compat layer, navegacion colmenas:selected, FloatingMicButton, migrar voice a expo-speech-recognition 2026-05-31 13:56:12 +02:00
App.js.bak feat(stt): sistema multi-motor con consenso whisper+sherpa-onnx+vosk 2026-05-30 20:27:48 +02:00
app.json feat(stt): sistema multi-motor con consenso whisper+sherpa-onnx+vosk 2026-05-30 20:27:48 +02:00
DOCUMENTACION-COMPLETA.md style: format all files with Prettier 2026-05-31 13:26:46 +02:00
eas.json feat(stt): sistema multi-motor con consenso whisper+sherpa-onnx+vosk 2026-05-30 20:27:48 +02:00
eslint.config.mjs chore(infra): configurar ESLint, Prettier, Husky, JSDoc y tests del core 2026-05-29 18:33:28 +02:00
index.js Initial commit: proyecto Expo + README 2026-05-29 14:12:48 +02:00
jest.config.js fix(ci): exclude .opencode/ from Jest testPathIgnorePatterns 2026-05-31 14:55:47 +02:00
LICENSE feat(license): add AGPLv3 license with dual licensing notice 2026-05-30 09:24:10 +02:00
opencode.json chore: update .opencode infrastructure files 2026-05-31 14:58:09 +02:00
package-lock.json fix(auditoria): corregir audio compat layer, navegacion colmenas:selected, FloatingMicButton, migrar voice a expo-speech-recognition 2026-05-31 13:56:12 +02:00
package.json fix(auditoria): corregir audio compat layer, navegacion colmenas:selected, FloatingMicButton, migrar voice a expo-speech-recognition 2026-05-31 13:56:12 +02:00
README.md feat(license): add AGPLv3 license with dual licensing notice 2026-05-30 09:24:10 +02:00
screenshot-all.cjs style: format all files with Prettier 2026-05-31 13:26:46 +02:00
screenshot-app.cjs style: format all files with Prettier 2026-05-31 13:26:46 +02:00
test-audit.json test(revolucion): 22 tests reales Whisper, 23 Calendario, 35 edge cases, limpiar duplicados 2026-05-30 11:31:26 +02:00
tsconfig.json feat(stt): sistema multi-motor con consenso whisper+sherpa-onnx+vosk 2026-05-30 20:27:48 +02:00

Cuaderno de Campo Apícola

🐝 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