Documento canónico de producto. Fuente de verdad de scope, restricciones y stack. Actualizar este fichero antes de cambiar el código o el ROADMAP.
- Nombre:
beeping_flutter - Tag: Cross-platform Flutter plugin for the Beeping ultrasonic SDK
- Versión inicial:
0.0.0(regla 0.x del ecosistema Beeping — bump coordinado a1.0.0solo al alcanzar production-readiness ecosistema completo) - Fecha de inicio:
2026-05-12 - Linear milestone: 🔌 Phase 10 — beeping_flutter (id
73c82c2b-faac-4111-8d18-cf435fceafa1) - Linear project: 🔊 Beeping Platform (id
a83369a5-3cb8-4fca-932d-ee33f6a7a00e) - License: Apache-2.0
beeping_flutter es el plugin federado oficial que expone el SDK Beeping (transmisión y recepción de datos vía señales acústicas ultrasónicas 18–22 kHz) a apps Flutter, consumiendo los SDKs nativos:
beeping-android(Maven Central) en Androidbeeping-ios(Swift Package Manager / CocoaPods) en iOS
Expone una API Dart instance-based (BeepingClient) con dos modos de operación interoperables — Local (procesamiento on-device vía SDKs nativos C++/JNI) y Cloud (HTTP a beepbox-server) — bajo el mismo strategy pattern.
- pub.dev score ≥ 130/160 en la primera versión publicada.
- ≥ 3 apps consumidoras (Beepster Flutter + otros 2) en producción para considerar Phase 10 cerrada.
- 0 warnings con
very_good_analysisen cualquier rama mergeable. - Coverage ≥ 80% en el package principal y en
_platform_interface.
- Federated plugin pattern obligatorio (Flutter best practice): un app-facing package + un platform interface + un package por plataforma.
- Apache-2.0 en todos los packages publicados (alineado con el resto del ecosistema OSS).
- Sin estado global en Dart: API instance-based, igual que en
beeping-android/beeping-ios. - Mobile-only en Phase 10 (Android + iOS). Soporte para Web (WASM via
@beeping/web), macOS, Linux y Windows es deferred — capturado endocs/PENDING.mdy como issues backlog en Linear sin milestone. - Dual mode (Local + Cloud) en scope desde la primera versión publicada: ambos modos deben funcionar y estar cubiertos por tests.
- Dependencias nativas pinneadas a release: nunca vendoring de
.aar/.xcframework— siempre consumir desde Maven Central / SPM / CocoaPods. - Apple-safe: el plugin nunca usa el micrófono sin user gesture explícito;
NSMicrophoneUsageDescriptiondocumentado en README + ejemplo.
- Plataformas soportadas (Phase 10): Android
minSdk 24+/ iOS 15+ - Distribución primaria: pub.dev — paquete
beeping_flutter+ sub-packages federated - Backup distribution: GitHub Releases con tarballs versionados (fallback documentado en
docs/setup/consume-from-github.md) - Entornos runtime:
- Dev: SDKs nativos en snapshot/SNAPSHOT Maven & SPM branch dev —
BEEPBOX_DEV_BASE_URLpor defecto - Prod: SDKs nativos pinneados a release semver —
BEEPBOX_PROD_BASE_URLpor defecto
- Dev: SDKs nativos en snapshot/SNAPSHOT Maven & SPM branch dev —
- Scaffold federated plugin (
beeping_flutter+beeping_flutter_platform_interface+beeping_flutter_android+beeping_flutter_ios) - API pública Dart
BeepingClient+Stream<BeepingContact>+ builders dual mode - Implementación Android consumiendo
beeping-androiddesde Maven Central - Implementación iOS consumiendo
beeping-iosdesde SPM/CocoaPods - Telemetry hook Dart con opt-out + tests de privacy
- Logging con
loggerpackage + trace-ID + Sentry sink - very_good_analysis strict + analysis_options.yaml + lint clean
- Suite de tests: flutter_test + mocktail + integration_test + golden_toolkit + Patrol
- Example app dentro del plugin con debug console
- CI/CD GitHub Actions (lint + test + integration_test en simulador)
- Publicación inicial en pub.dev (score >130, topics, license, example)
- ❌ Soporte Web (WASM) — usar
@beeping/webdirectamente en Flutter Web hasta que exista wrapper Dart - ❌ Soporte macOS / Linux / Windows
- ❌ Background listening (mic activo con app en background) — bloqueado por restricciones Apple
- ❌ Custom encoder modes más allá de los expuestos por los SDKs nativos
- ❌ UI components prefab (botones, listeners visuales) — solo lógica + ejemplo
- ❌ Migración del scaffold legacy (no hay scaffold previo — proyecto greenfield)
Toda adición/eliminación al scope dispara entrada en docs/ROADMAP_CHANGELOG.md con trigger Scope change. Los items deferred se capturan en docs/PENDING.md con id pending-NNN + entrada espejo en Linear (issue sin milestone, etiqueta backlog).
- Idiomatic Dart: API que un Dart developer puede leer sin saber nada de C++/JNI/Swift.
- Reactive-first:
Stream<>para eventos,Future<>para acciones puntuales. Nunca callbacks. - Errores explícitos:
Result<T, BeepingError>othrowtipado — nuncanullambiguo. - Same surface dual mode: el cliente no debe darse cuenta si está en Local o Cloud salvo por explicit configuration.
- Privacy by default: telemetry opt-in, no PII jamás, samples in-memory only.
- Test-driven changes: ningún PR sin tests del nivel adecuado (unit + integration mínimo).
- No magic: el plugin no monkey-patcha el WidgetsBinding ni hace setup global automático. Todo es explícito.
// 1. Crear cliente
final client = BeepingClient.builder()
.apiKey(env.beepingApiKey)
.mode(BeepingMode.cloud) // o .local
.build();
// 2. Escuchar contactos entrantes
final subscription = client.contacts.listen((contact) {
print('Beep received: ${contact.payload}');
});
// 3. Emitir un beep
await client.send(payload: 'hello-world');
// 4. Liberar
await subscription.cancel();
await client.dispose();BeepingError.unauthorized(API key inválida)BeepingError.micPermissionDenied(Android/iOS: usuario rechazó NSMicrophoneUsageDescription)BeepingError.transportUnavailable(Cloud mode: no internet; Local mode: speaker no disponible)BeepingError.payloadTooLong(max 32 bytes definido por core)BeepingError.invalidState(operación inválida en el lifecycle actual: e.g. send después de dispose)- Errores nativos (
PlatformException) → mapeados aBeepingError.platform(message, stack)
- Latencia send (Local): < 200 ms desde call hasta primer sample emitido
- Latencia decode (Local): < 500 ms desde primer sample válido recibido hasta
contactemitido - Cold start client init: < 100 ms en device gama media (Pixel 6 / iPhone 13)
- Footprint runtime: < 3 MB heap en idle, < 12 MB durante session activa
- Battery impact: < 2%/h con session activa continua (medido en Pixel 6 + iPhone 13)
- Crash rate: < 0.1% sessions (Sentry crash-free rate ≥ 99.9%)
| Capa | Tool |
|---|---|
| Lenguaje | Dart 3.5+ |
| Framework | Flutter 3.24+ |
| Plugin pattern | Federated (4 packages) |
| Lint | very_good_analysis strict (score-relevant rules en analysis_options.yaml) |
| Format | dart format (rule of 80 cols) |
| Tests unitarios | flutter_test + mocktail |
| Tests property | (vía glados opcional, candidato futuro) |
| Tests golden | golden_toolkit (solo aplicable en example app) |
| Tests integration | integration_test (canal nativo end-to-end) |
| Tests E2E | patrol (real device test en CI matrix iOS + Android) |
| Logging | logger package + trace-ID propagation |
| Telemetry/crash | Sentry (sentry_flutter) |
| HTTP (Cloud mode) | dio + retry interceptor + OpenAPI-generated client desde beepbox-server |
| Coverage | lcov + coverage_badge en README |
| Release tool | release-please (Conventional Commits) |
| CI/CD | GitHub Actions |
| Package | Rol |
|---|---|
beeping_flutter |
App-facing. API BeepingClient, builders, error types, models. |
beeping_flutter_platform_interface |
Contrato Method/Event channels + tipos compartidos. |
beeping_flutter_android |
Implementación Kotlin que delega a beeping-android. |
beeping_flutter_ios |
Implementación Swift 6 que delega a beeping-ios. |
example/ |
App Flutter demo con debug console (no publicada, dentro del repo). |
- beeping-android (Maven Central) — JNI bridge a
beeping-core(C++20) - beeping-ios (SPM / CocoaPods) — ObjC++ bridge a
beeping-core - beepbox-server (HTTP) — Cloud mode endpoints
- Sentry — opcional, opt-in via
BeepingClient.builder().sentryDsn(…) - pub.dev — distribución
- Firebase Test Lab — Patrol E2E en CI (real devices iOS + Android)
- Federated pattern over single-package: futuras plataformas (Web, macOS) requieren swap independiente sin breaking changes en la API consumer-side.
diooverhttp/chopper: interceptor pattern más maduro, mejor retry/backoff support.Stream<>overValueListenable<>/ Notifier: alineado con resto del ecosistema (FlowKotlin,AsyncStreamSwift,ObservableJS).mocktailovermockito: codegen-free, alineado con tendencia 2024+ de Flutter community.loggeroverdart:developer.log: estructurado, multi-sink, opt-in PII redaction.- Sentry over Firebase Crashlytics: el ecosistema Beeping ya estandariza Sentry (cross-stack).
- Native pin via Maven/SPM, not vendoring: dependency-driven SBOM y supply chain queries más limpios.
- Developers Flutter que ya tienen una app cross-platform y quieren añadir capacidades de descubrimiento de proximidad sin internet (replace QR / NFC / BLE).
- Indie devs construyendo apps party / classroom / IoT pairing que necesitan offline multi-device sync.
- Equipos enterprise evaluando audio side-channel como alternativa a BLE en hardware viejo.
| Métrica | Target Phase 10 |
|---|---|
| pub.dev score | ≥ 130 |
| Apps consumidoras producción | ≥ 3 (Beepster + 2) |
| GitHub stars | ≥ 50 en T+90 días post-publish |
| Test coverage | ≥ 80% main package, ≥ 90% platform_interface |
| Lighthouse a11y (example app) | ≥ 95 |
| Sentry crash-free sessions | ≥ 99.9% |
| Sample app first-paint | < 1.5 s |
| Riesgo | Probabilidad | Impacto | Mitigación |
|---|---|---|---|
beeping-android no aprobado en Maven Central antes de Phase 10 cierre |
M | A | Fallback a GitHub Packages Maven, documentado en docs/setup/consume-from-github.md |
beeping-ios no aprobado en CocoaPods Trunk en plazo |
M | A | SPM primario; consume directo desde GitHub Releases mientras |
| Apple rechaza app demo por uso mic background | B | A | Demo solo foreground + user gesture; documentado en README |
| Patrol Firebase Test Lab quota cap | M | M | Cap tests/PR; smoke matrix solo en main + release-please PRs |
| pub.dev score < 130 | M | M | Pre-publish check con pana en CI; bloqueante para release |
| Federated plugin pattern complexity | M | M | Spike inicial (BEE-83 + BEE-84) antes de impls; ADR documentado |
1 milestone (Phase 10) con 11 tasks (63 SP) ya creadas en Linear:
| Task | Título | SP | Entregable | Versión |
|---|---|---|---|---|
| BEE-83 | 🌱 Crear repo + scaffold federated plugin + Apache-2.0 | 3 | Repo público + 4 packages | 0.0.1 |
| BEE-84 | 🏗️ Platform interface package | 5 | Contrato Method/Event channels | 0.0.2 |
| BEE-91 | 🧼 very_good_analysis lint estricto | 2 | analysis_options.yaml clean | 0.0.3 |
| BEE-87 | 🌊 API pública Dart: BeepingClient + builders dual mode |
5 | API Dart documentada | 0.0.4 |
| BEE-88 | 🪵 Logging con logger + trace-ID + Sentry sink |
3 | Logging multi-sink | 0.0.5 |
| BEE-89 | 📡 Telemetry hook con opt-out + tests privacy | 3 | Telemetry pluggable | 0.0.6 |
| BEE-85 | 🤖 Impl Android: consume beeping-android Maven |
8 | Plugin Android funcional | 0.0.7 |
| BEE-86 | 🍎 Impl iOS: consume beeping-ios SPM/CocoaPods |
8 | Plugin iOS funcional | 0.0.8 |
| BEE-92 | 📱 Example app con debug console | 5 | App ejecutable iOS+Android | 0.0.9 |
| BEE-90 | 🧪 Tests: flutter_test + mocktail + integration + golden + Patrol | 13 | Suite completa CI | 0.0.10 |
| BEE-93 | 📦 Publicación en pub.dev (score >130) | 8 | Plugin live en pub.dev | 0.1.0 |
Total: 63 SP. Fecha de fin estimada (con margen 20%) → calculada en docs/ROADMAP.md.