Skip to main content

Cross-Platform Lifestyle App

Cross-platform travel and booking app with offline maps and editorial content

Private
Cross-Platform Lifestyle App hero
The Problem

Cross-Platform Lifestyle App

A cross-platform travel and booking app built with Flutter for iOS and Android. Features map integration, headless CMS for editorial content, Firebase analytics, and a BLoC-based architecture with staging and production build flavors.

iOS + Android

Platform

Flutter Engineer

Role

My Role
Flutter DevelopmentAPI IntegrationCI/CD Pipeline
Process

From Design to Both Stores

01

Architecture & State Management

Feature-first architecture where each feature owns its view, provider, and state files. We used BLoC for complex stateful flows and Riverpod StateNotifier for simpler screens. Retrofit code generation gives us type-safe API clients without writing boilerplate.

02

Maps & Location Features

Mapbox with custom markers, clustering, and location-based search. I added offline map caching via Hive for areas with poor connectivity. Thousands of points on the map, no frame drops.

03

CMS-Driven Content

The headless CMS for articles, guides, and rich text with embedded media. I built a rendering pipeline that transforms the CMS rich text node tree into Flutter widgets with proper styling and image optimization. Harder than it sounds.

04

Multi-Flavor Deployment

Staging and production build flavors with separate bundle IDs, API endpoints, and Firebase projects. Codemagic runs CI/CD: PRs trigger test builds, merges to main deploy staging, tagged releases go to production stores.

Key Features

Explore Without Friction

01

Interactive Maps with Offline Support

Mapbox renders location data with custom-styled markers that cluster at zoom levels. Search, filter, navigate to points of interest. When connectivity drops, previously viewed map tiles and location data are still available from Hive local storage. The app degrades gracefully instead of showing empty screens.

02

CMS-Powered Editorial Content

Content editors manage articles and guides in a headless CMS without ever talking to a developer. The app fetches structured content via the CMS API and renders it through a custom widget tree handling rich text, embedded images, videos, and cross-references between articles.

03

Feature-First Architecture

Each feature is a self-contained directory with its own view, state, and provider files. go_router gives us declarative, deep-linkable routing. New features are additive. They never require modifying existing feature code.

Technical Deep Dive

Under the Hood

Built With
FlutterDartCross-Platform
Flutter AppBLoCMapboxHeadless CMSFirebaseAPI

Key Technical Decisions

BLoC + Riverpod Hybrid

The team initially wanted to pick one. We didn't. BLoC for complex multi-step flows (onboarding, checkout), Riverpod StateNotifier for simpler read-heavy screens (content lists, settings). Boilerplate stays proportional to complexity instead of being one-size-fits-all.

Headless CMS Rich Text to Flutter Widgets

The headless CMS delivers rich text as a nested node tree, not HTML. We built a recursive renderer that maps each node type to a Flutter widget. Headings, paragraphs, embedded assets, hyperlinks. Unknown node types fall back to plain text instead of crashing. The edge cases (nested lists inside blockquotes, images with captions) are where all the time went.

Dynamic Config Generation

Build-time code generation creates environment-specific configuration classes. Staging and production flavors get different API URLs, feature flags, and analytics keys. No runtime checks, no if-else per environment. Runs as a pre-build step in Codemagic.

Learnings

What I Learned

Pick both and stop arguing

The BLoC vs. Riverpod debate ate two days. Using both reduced boilerplate by about 30% compared to forcing BLoC everywhere. Match the tool to the problem, not the other way around.

We estimated the CMS renderer at one week

It took two and a half. The headless CMS rich text format is well-structured, but edge cases multiply fast. Nested lists inside blockquotes, images with captions, inline code spans. Building it as a recursive widget tree (not string parsing) was the right call, but the scope was humbling.

We added build flavors in month three. That was a mistake

Spent a week untangling hardcoded environment references that would have been trivial config on day one. Set up staging/production flavors before writing your first feature.

Next ProjectSee more projects →
Trusted Infrastructure Platform

Trusted Infrastructure Platform

Decentralized identity platform with custom auth, iOS client, and admin dashboard