Relocate — Flutter Starter Kit for Neighborhood Research by Dusko LicaninRelocate — Flutter Starter Kit for Neighborhood Research by Dusko Licanin

Relocate — Flutter Starter Kit for Neighborhood Research

Dusko Licanin

Dusko Licanin

Relocate — school ratings map
Relocate — school ratings map

Introduction

Relocate is a cross-platform mobile app that helps people researching a US neighborhood see what living there actually looks like — census demographics, school ratings, crime patterns, flood risk, weather, cost of living, and resident stories on one map.
My role was to build the Phase 1 Flutter starter kit: app shell, navigation, design system, subscription flow, onboarding, Mapbox integration, crash/observability pipeline. The product direction, business model, and post-handoff development are owned by the client, who continues development on their side. I was a collaborator on this engagement, not the sole builder or owner — the brief was a production-ready foundation the client team could keep building on.

The Challenge

Mapbox N+1 platform-channel calls. The school, offender, and nearby screens each rendered hundreds of map annotations one at a time, each create() round-tripping through a platform channel — visibly slow on mid-range Android. Switched to createMulti(options) so the entire batch crosses the channel once.
RevenueCat entitlement Unicode trap. The original entitlement ID was Relocate․app Pro — that dot is a U+2024 ONE DOT LEADER, not an ASCII period, copy-pasted from a designed mockup. Visually equal, codepoint-unequal, so the SDK returned active: false in production. Renamed to plain ASCII pro and documented the rename for the RevenueCat dashboard.
Trial paywall CTA gated on real SDK data. The CTA was previously hardcoded — users in regions without an introductory offer saw a "Start free trial" button that resolved to a normal purchase. Now reads package.storeProduct.introductoryPrice directly; CTA only shows trial wording when the SDK surfaces one.
Sentry filter for VM/farm SIGABRTs. Firebase Test Lab's Robo crawler and other emulators were flooding Sentry with native crashes that never affect real users. A beforeSend filter fingerprints four signals — Google buildbot kernel banner, sub-phone screen geometry, malformed build IDs, <=2 processor count — and drops events that match any.
Mapbox token init race condition. setAccessToken() returns void but writes to a pigeon channel asynchronously. Without an await before runApp, MapWidget could mount before the token landed on the native iOS SDK — blank tiles on cold start. Bounded await with a 500ms timeout fallback fixes the warm-sim race without risking deadlock on the cold-boot pigeon handshake.
Relocate — after kill state recovery
Relocate — after kill state recovery

Our Solution

Flutter 3.38+ with Riverpod 3 and GoRouter 17. Feature-first layout under lib/features/ with data-heavy features split into presentation/, domain/, data/ layers. Shared code in lib/core/. Riverpod 3 with code generation drives state and async data; ref.invalidate after every write keeps caches honest. Freezed models guarantee immutability across async boundaries.
Mapbox integration with batched annotations, geocoding-driven address search, light/dark style swap, and defensive disposal
RevenueCat paywall with trial-aware CTA reading introductoryPrice from the SDK directly
Dual crash reporting: Sentry + Crashlytics chained (never replacing) FlutterError.onError, with VM/farm SIGABRT filter
RelocateNeighborhoodLayout scaffold — AppBar, drawer, glassmorphic 10-tab bar keeping all sub-screens consistent
Two complete themes: "Informed Curator" light (Manrope + Inter) and tactical dark (JetBrains Mono headlines, cyan #00F2FF primary)
Features delivered: 4-slide onboarding carousel, Firebase Phone Auth with country picker, moving checklist, favorites, profile, settings, stories (feed + detail + create), cost-of-living, weather, flood, offender registry, commute calculator
Release builds with obfuscation, split debug info, Sentry symbol upload, and Crashlytics native symbol upload
Relocate — iPhone Pro screenshot
Relocate — iPhone Pro screenshot
Relocate — iPhone Pro Max screenshot
Relocate — iPhone Pro Max screenshot

Demo

Outcome

The Phase 1 starter kit was handed off to the client, who owns the product and continues development on their side. The codebase runs to 38,711 lines across lib/ (excluding generated files), 30 Riverpod providers, 40 Freezed models, 45 tests, and 625 commits authored.
The client confirmed they're happy for this to be featured as a case study, framed accurately as a prototype and starter kit — since significant work remains before a public release.

Conclusion

Relocate is a collaborator engagement, not a solo product — and that distinction matters. The brief was to deliver a production-ready Flutter foundation: clean architecture, working paywall, real Mapbox integration, dual crash reporting. That's what shipped.
The interesting technical work was in the details: a Unicode codepoint hiding in an entitlement ID, a batch API call that cut hundreds of platform-channel round-trips to one, a beforeSend filter that keeps emulator noise out of production alerts. The foundation is solid. The client builds from here.
Like this project

Posted Jul 1, 2026

Flutter foundation for a US neighborhood-research app — Mapbox, Firebase, RevenueCat paywall, Sentry + Crashlytics. Collaborator engagement, delivered as a production-ready starter kit.