iOS · App Store
Native Swift app: today’s free forecast, saved hunt pins, maps, wind check, and track. Background location only when the hunter opts in for a sit. Store listing: DeerCast — Prep. Predict. Pursue.
App StoreA native hunting app — not a website with a thin wrapper. Hunters open iOS or Android in the dark, see today’s free whitetail forecast for their pin, then decide whether 06:40 or 16:10 is the hour worth sitting.
Was ausgeliefert wurde: 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.
Both stores get the same Node.js API. There is no staff web app on this engagement. If it does not work with gloves, one bar of LTE, and a 5 a.m. battery, it does not ship.
Native Swift app: today’s free forecast, saved hunt pins, maps, wind check, and track. Background location only when the hunter opts in for a sit. Store listing: DeerCast — Prep. Predict. Pursue.
App StoreNative Kotlin app with the same forecast, map objects, and track flow. Offline map edits write locally, then sync when the ridge has signal again — same contract as iOS.
Play StoreBefore this build, a hunter with two vacation days stacked a national weather icon, a moon calendar screenshot, and a mapping app that did not know the rut window. “Cold and cloudy” is not an hour. Sitting 05:30–11:00 because the icon looked good burned the only weekday they had.
The engine scores each hour from local temperature, wind, barometric trend, cloud cover, precip, lunar feeding windows, and season (pre-rut / rut / late). Today’s forecast is free. Longer horizons sit behind IAP, same as the stores.
Today · Cedar Ridge
CR-WEST · free day · cached
NW 8 mph · 34°F · baro falling · moon 28%
A 12-hour weather blob. Sit all morning “just in case.”
Each hour has a score for that pin. Cole sits 07:00–08:30 and leaves.
Phone weather showed Des Moines or the county seat — not the farm 40 minutes out.
Temp, wind, barometer, rain, and moon are scored for the saved pin (CR-WEST), not the nearest town.
Hunt plan in one app, map in another, wind in a third.
Pins, food plots, wind check, radar, and crop history sit in the same native map.
Guess the blood trail from a group text.
Mark the hit on an anatomical model; wait/search guidance is on the same phone.
Spinner. Then a screenshot from last night.
Last forecast + map objects cache on device. Sync when LTE returns.
They remembered to check at lunch. Window was 07:00.
Optional push when tomorrow’s Prime hour lands on a saved pin.
Native map layers: property info, hunting land, custom waypoints, wind check, food plots, live Doppler, virtual rain gauges, aerial, and crop history. Offline edits queue locally so a hunter can drop a pin with no service.
Track is a separate flow: tap the hit on the model, log time and weather already on the pin, then follow wait-vs-search guidance. Session documents land in MongoDB; the hunter identity stays in PostgreSQL.
Two stores on purpose. Relational data that must not drift (who paid, which pin, which parcel) lives in Postgres. High-write, nested, time-bucketed weather and scores live in MongoDB so an hour document can be replaced without a 24-column update.
Source of truth for identity and hunt assets. Node.js talks to it over a connection pool. iOS/Android never open the database — only the API.
Document store for anything that arrives as a nested hour array or a radar blob. Indexed on locationId + date.
{
"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"
}
Node.js workers pull local weather and moon for every active pin in PostgreSQL. Raw frames land in MongoDB.
The movement engine writes a 24-hour document. Prime / Good / Slow is stored per hour, not as a daily slogan.
iOS and Android GET the day for their pins. Today is free. Entitlement for 14-day range is checked in Postgres.
On the ridge the phone reads the cache. Optional push already fired if tomorrow’s Prime hour matched a saved pin.
This case study is mobile-only. Native iOS and Android talk REST (and a light sync channel) to a Node.js API. PostgreSQL holds hunters, devices, IAP receipts, pins, and map geometry. MongoDB holds forecast documents, weather ingest, radar, track sessions, and the community feed.
Stores are not interchangeable. You do not put 24 nested hour objects in a Postgres row for every pin every night, and you do not put IAP entitlements in a Mongo document that a hunter can fork.
Native forecast, maps, track, push, offline queue. Same API contract on both stores.
Auth, entitlements, forecast read, map CRUD, weather jobs, push fan-out.
Users, devices, App Store / Play receipts, hunt pins, waypoints, food plots, parcels.
Hour-by-hour forecast documents, weather ingest, radar, track sessions, feed posts.
Hunters plan around Prime hours on a named pin. Vacation days stop being “sit from dark to 11 because AccuWeather said cloudy.”
Forecast, wind, parcels, and track share a native shell. No three-app shuffle with gloves on.
If a Tuesday score looks wrong, weather_ingest in MongoDB and the pin in PostgreSQL still exist. The model can be retrained; the receipt cannot be guessed.
We ship native iOS and Android against a Node.js API, with PostgreSQL for accounts and MongoDB for time-series documents — the same split used on DeerCast.