DeerCast
Prep. Predict. Pursue

Una app nativa de caza — no un sitio web con una capa fina. Los cazadores abren iOS o Android en la oscuridad, ven la previsión gratuita de hoy de cola blanca para su pin y deciden si 06:40 o 16:10 es la hora que vale la pena esperar.

Qué se entregó: native iOS (App Store) and native Android (Play Store). Same Node.js API. PostgreSQL for accounts, pins, maps, and receipts. MongoDB for the hour-by-hour forecast documents and weather ingest. No Super Admin web console on this product — the phone is the product.

iOS Android PostgreSQL · MongoDB
Ciervo de cola blanca en un food plot del Midwest al amanecer, bosque y un ladder stand al borde
07:10 Prime
NW 8 mph
Offline cache
Cedar Ridge, Iowa · CR-WEST pin
Timber · food plot · stand — the area the forecast is scored for
iOS · Android
iOS Native · App Store
Android Native · Play Store
PostgreSQL Users, pins, maps, IAP
MongoDB Hourly forecast documents

Solo móvil. iOS y Android.

Ambas tiendas reciben la misma API Node.js. No hay app web de personal en este proyecto. Si no funciona con guantes, una barra de LTE y batería a las 5 a.m., no se entrega.

iOS · App Store

App nativa Swift: el pronóstico gratuito de hoy, pines de caza guardados, mapas, chequeo de viento y pista. Ubicación en segundo plano solo cuando el cazador lo activa para una espera. Ficha de tienda: DeerCast — Prep. Predict. Pursue.

App Store

Android · Play Store

App nativa Kotlin con la misma previsión, objetos de mapa y flujo de seguimiento. Las ediciones de mapa offline se escriben en local y se sincronizan cuando la cresta vuelve a tener señal: el mismo contrato que iOS.

Play Store

A weather app is not a hunt plan.

Antes de este desarrollo, un cazador con dos días de vacaciones apilaba un icono meteorológico nacional, una captura de calendario lunar y una app de mapas que no conocía la ventana del celo. “Frío y nublado” no es una hora. Esperar 05:30–11:00 porque el icono se veía bien quemaba el único día laborable que tenía.

  • Sin resolución por horaLos pronósticos genéricos decían “buena mañana”. No decían 07:10–08:40 en esta cresta tras 0.4" de lluvia nocturna.
  • Los mapas vivían en otra appWaypoints, viento y linderos no estaban junto a la puntuación de movimiento. Cambiar de app en un puesto es cómo se caen los teléfonos.
  • Sin ruta de recuperaciónUn impacto a última luz era un hilo de foro, no una pista estructurada en el mismo teléfono que llamó a la espera.
Ciervo de cola blanca en el borde de un campo a última luz

Cole H. · Cedar Ridge, Iowa · pin CR-WEST

  1. 21:12 lun — Abre el iPhone en la cocina. Hoy + mañana gratis para CR-WEST. Martes 07:00–08:30 marcado Prime tras lluvia nocturna y barómetro en descenso. Pone una alarma de espera. Nada que imprimir.
  2. 05:48 mar — Entra en Android (teléfono del trabajo). El pronóstico sigue en la caché del dispositivo: la cresta no tiene LTE. Chequeo de viento: NW 8. Conserva el pin del lado oeste; el food plot del este sería un remolino.
  3. 07:22 — Ventana de movimiento por la que esperó. Dos hembras, luego un macho maduro en el borde del campo. La hora coincidió con lo que MongoDB puntuó la noche anterior, no un genérico “nublado y fresco”.
  4. 16:40 — La espera opcional de tarde es Slow. No quema el segundo día de vacaciones. Track no se usa. Eso sigue siendo un acierto.

Movimiento hora a hora — para ese pin

El motor puntúa cada hora con temperatura local, viento, tendencia barométrica, nubosidad, precipitación, ventanas lunares de alimentación y temporada (pre-celo / celo / tardío). La previsión de hoy es gratuita. Horizontes más largos van detrás de IAP, igual que en las tiendas.

Today · Cedar Ridge

Whitetail forecast

CR-WEST · free day · cached

05:00
Slow
06:00
Build
07:00
Prime
08:00
Prime
09:00
Good
10:00
Slow

NW 8 mph · 34°F · baro falling · moon 28%

Cazador consultando un teléfono desde un tree stand a primera luz
En el puesto Forecast already on the device

Lo que el cazador hace de verdad en la app

01 · Predict

Previsión hora a hora

Antes

A 12-hour weather blob. Sit all morning “just in case.”

Después

Cada hora tiene una puntuación para ese pin. Cole espera 07:00–08:30 y se va.

02 · Weather

Tiempo en el pin de caza

Antes

El tiempo del teléfono mostraba Des Moines o la capital del condado, no la granja a 40 minutos.

Después

Temp, viento, barómetro, lluvia y luna se puntúan para el pin guardado (CR-WEST), no para el pueblo más cercano.

03 · Map

Waypoints, parcels, wind, plots

Antes

Hunt plan in one app, map in another, wind in a third.

Después

Pines, food plots, chequeo de viento, radar e historial de cultivo están en el mismo mapa nativo.

04 · Track

Hit location → recovery

Antes

Adivinar el rastro de sangre desde un grupo de texto.

Después

Marcar el impacto en un modelo anatómico; la guía de esperar/buscar está en el mismo teléfono.

05 · Offline

Cresta sin cobertura

Antes

Spinner. Luego una captura de anoche.

Después

Last forecast + map objects cache on device. Sync when LTE returns.

06 · Push

Window alerts

Antes

They remembered to check at lunch. Window was 07:00.

Después

Optional push when tomorrow’s Prime hour lands on a saved pin.

Cazador planificando una espera con teléfono y mapa de papel al amanecer

Explorar en el portón. Recuperar después del disparo.

Capas de mapa nativas: info de propiedad, terreno de caza, waypoints a medida, chequeo de viento, food plots, Doppler en vivo, pluviómetros virtuales, aérea e historial de cultivo. Las ediciones offline se encolan en local para que un cazador pueda soltar un pin sin cobertura.

El seguimiento es un flujo aparte: toque el impacto en el modelo, registre hora y tiempo ya en el pin, luego siga la guía esperar-vs-buscar. Los documentos de sesión aterrizan en MongoDB; la identidad del cazador se queda en PostgreSQL.

PostgreSQL para el cazador. MongoDB para las horas.

Dos tiendas a propósito. Los datos relacionales que no deben desalinearse (quién pagó, qué pin, qué parcela) viven en Postgres. El tiempo y las puntuaciones de alta escritura, anidados y por cubos de tiempo viven en MongoDB para que un documento de hora se pueda reemplazar sin un update de 24 columnas.

PostgreSQL

Fuente de verdad para identidad y activos de caza. Node.js habla con ella por un pool de conexiones. iOS/Android nunca abren la base: solo la API.

  • users / devicesEnlaces de cuenta Apple y Google, tokens push, última versión de la app.
  • subscriptions / receiptsIAP de App Store y Play, derechos Elite / Pro / Unlimited, ventanas de prueba.
  • hunt_locationsPines con nombre (CR-WEST), lat/lng, zona horaria: la clave con la que une el job de pronóstico.
  • waypoints, food_plots, parcel_savesObjetos de mapa estructurados con claves foráneas hunter_id.

MongoDB

Almacén de documentos para lo que llega como array anidado de horas o un blob de radar. Indexado en locationId + date.

  • forecast_daysOne document per pin per civil day: 24 hour scores, wind, temp, baro, moon, rut phase.
  • weather_ingestObservaciones crudas de proveedor/NWS que consumió el scorer, guardadas para auditoría cuando un cazador dice “esta hora estaba mal”.
  • radar_frames / rain_gaugesTiles de corta vida que lee la superposición del mapa.
  • track_sessions / community_postsDiagramas de impacto, fotos, ítems de feed: el esquema varía; Postgres solo guarda el id del dueño.
MongoDB · forecast_days · CR-WEST · 2026-11-18 Scored
{
  "locationId": "loc_cr_west",   // FK in PostgreSQL hunt_locations
  "date": "2026-11-18",
  "hours": [
    { "h": 7, "score": 92, "label": "Prime", "wind": "NW 8", "tempF": 34, "baro": "falling" },
    { "h": 8, "score": 86, "label": "Prime", "wind": "NW 8", "tempF": 35, "baro": "falling" }
  ],
  "moonPct": 28,
  "season": "rut",
  "precipInOvernight": 0.41,
  "engine": "v3.4"
}
MongoDB document locationId is a PostgreSQL hunt_locations row

De la ingesta meteorológica a una hora Prime en el teléfono

01

Ingest

Node.js workers pull local weather and moon for every active pin in PostgreSQL. Raw frames land in MongoDB.

02

Score

El motor de movimiento escribe un documento de 24 horas. Prime / Good / Slow se guarda por hora, no como un eslogan diario.

03

Sync

iOS y Android hacen GET del día para sus pines. Hoy es gratis. El derecho para el rango de 14 días se comprueba en Postgres.

04

Sit

En la cresta el teléfono lee la caché. El push opcional ya disparó si la hora Prime de mañana coincidía con un pin guardado.

Native phones. Postgres + MongoDB behind Node.js.

Este caso de estudio es solo móvil. iOS y Android nativos hablan REST (y un canal ligero de sync) con una API Node.js. PostgreSQL guarda cazadores, dispositivos, recibos IAP, pines y geometría de mapa. MongoDB guarda documentos de previsión, ingesta meteorológica, radar, sesiones de seguimiento y el feed de comunidad.

Los almacenes no son intercambiables. No se meten 24 objetos de hora anidados en una fila Postgres por cada pin cada noche, y no se meten derechos IAP en un documento Mongo que un cazador pueda bifurcar.

iOS native Android native Node.js API PostgreSQL MongoDB Offline cache
iOS & Android

Native forecast, maps, track, push, offline queue. Same API contract on both stores.

Node.js API

Auth, entitlements, forecast read, map CRUD, weather jobs, push fan-out.

PostgreSQL

Users, devices, App Store / Play receipts, hunt pins, waypoints, food plots, parcels.

MongoDB

Previsión hora a hora documents, weather ingest, radar, track sessions, feed posts.

Qué cambió después del go-live

Hours, not slogans

Los cazadores planifican alrededor de horas Prime en un pin con nombre. Los días de vacaciones dejan de ser “esperar de oscuro a las 11 porque AccuWeather dijo nublado.”

Una app en el puesto

Previsión, viento, parcelas y seguimiento comparten una shell nativa. Sin baile de tres apps con guantes.

Datos que se pueden auditar

Si una puntuación del martes se ve mal, weather_ingest en MongoDB y el pin en PostgreSQL siguen existiendo. El modelo se puede reentrenar; el recibo no se puede adivinar.

¿Necesita una app móvil de clase previsión?

Entregamos iOS y Android nativos contra una API Node.js, con PostgreSQL para cuentas y MongoDB para documentos de series temporales: la misma división usada en DeerCast.