← All work

Independent technical case study

MultiBook

A private marketplace built as a production-oriented Flutter application for iOS and Android, supported by a Go API, PostgreSQL, and selected Firebase services.

Role
Creator & Flutter Developer
Focus
Flutter architecture and implementation, Customer and provider feature delivery, API design and backend integration
Platform
Flutter, Dart, Go, PostgreSQL, Firebase

Customer experience

From discovery to booking

The primary product journey across stays, services, scheduling, confirmation, and reservation management.

01

Explore stays and services

MultiBook customer home with stay discovery, search, filters, and recommendations
Discover stays
MultiBook customer explore screen with curated travel collections
Explore collections
MultiBook customer home showing nearby services and appointment pricing
Browse services
MultiBook service detail with business information and bookable services
Review a provider
02

Complete and manage a booking

MultiBook customer appointment flow with service, provider, date, and time selection
Choose service and provider
MultiBook customer appointment confirmation with service, schedule, duration, and payment details
Confirm the appointment
MultiBook customer booking list with stays and services tabs
Track bookings
MultiBook customer booking details with reservation status and price breakdown
Review booking details

Challenge

What needed to be made clear

Design one product that supports customers and providers, two reservation models, multiple businesses per provider, and consistent availability and booking rules across mobile and backend boundaries.

Solution

A structure built around change

Separate customer and provider journeys while keeping shared domain behavior explicit. The Flutter client depends on action-specific use cases and repository contracts, while the Go API owns authorization, validation, availability, and transactional business rules.

Engineering decisions

The decisions behind the Flutter application

  1. Structure the Flutter codebase around feature boundaries and clean dependency direction, with presentation, use cases, repository contracts, and data adapters carrying distinct responsibilities.
  2. Use BLoC and Cubit for business and asynchronous state, while keeping short-lived interaction state scoped to the Flutter widget lifecycle.
  3. Represent API outcomes as typed Dart results and translate transport failures centrally, giving features consistent loading, validation, authorization, connectivity, and server-failure paths.
  4. Centralize routing and session lifecycle so onboarding, authentication, user roles, protected navigation, realtime subscriptions, and sign-out remain coordinated.
  5. Keep pricing, availability, authorization, and reservation integrity on the Go and PostgreSQL boundary while Flutter owns product interaction, state, navigation, and platform delivery.

System design

How the parts work together

01Client

Flutter application

Customer and provider journeys, explicit UI state, navigation, localization, and platform integrations for iOS and Android.

02Application boundary

Go REST API

Authentication context, authorization, validation, booking rules, availability, discovery, chat, and reporting endpoints.

03Business data

PostgreSQL

Profiles, businesses, offerings, reservations, availability, promotions, reviews, notifications, chat, and reporting projections.

04Platform services

Firebase

Authentication, image storage, and push delivery, kept separate from the source of business data.

Product scope

MultiBook is a two-sided marketplace for stays and scheduled services. Customers can discover businesses, search and filter results, save places, complete bookings or appointments, manage reservations, leave reviews, and chat with providers.

Providers can create and manage multiple businesses, define offerings and availability, process reservations, run promotions, follow earnings, and communicate with customers. The selected business becomes the active domain context across the provider experience.

Flutter implementation

The mobile application is organized around feature boundaries for customer, provider, and shared journeys. Flutter is responsible for much more than rendering screens: it coordinates authentication state, navigation, API communication, realtime subscriptions, local preferences, platform integrations, and explicit UI state across two distinct user roles.

Layered feature architecture

The Flutter codebase applies clean architecture within feature-oriented customer, provider, and shared areas. Presentation coordinates user intent and renders state, action-specific use cases express application operations, repository contracts define stable boundaries, and data adapters connect those contracts to remote and platform services.

The boundaries keep feature behavior independent from infrastructure details and provide focused surfaces for testing, maintenance, and further product development.

Predictable state ownership

BLoC and Cubit coordinate business flows and asynchronous state across discovery, availability, booking, payment, business management, chat, and reporting. Short-lived interaction state remains local to the widget lifecycle through Flutter Hooks.

State transitions model loading, data, empty, validation, and recoverable failure paths explicitly. Action-specific use cases keep behavior cohesive and make state ownership clear across complex customer and provider journeys.

Typed networking and failures

Authenticated REST communication is exposed to Flutter features through typed results. Firebase supplies the active identity token, typed Dart models preserve the API contract, and a shared repository executor converts transport exceptions into a stable application failure model.

The model distinguishes validation, authentication, authorization, not-found, connectivity, server, and unexpected failures. BLoC and Cubit can then turn those outcomes into feature-specific UI states and user-facing messages without exposing transport diagnostics to the interface.

GoRouter centralizes routes and guards onboarding and authentication. After sign-in, a dedicated Flutter entry coordinator selects the customer journey, the provider workspace, or initial business setup from the authenticated profile and active business context. Customer and provider areas use independent persistent tab navigation, allowing each journey to preserve its own state.

Session-scoped SSE subscriptions, notification registration, and protected navigation are coordinated during sign-out. Active streams are cancelled before Firebase ends the session so authenticated realtime work does not continue into the signed-out state.

Mobile delivery concerns

The project has separate development and production flavors with independent application identifiers, API configuration, Firebase projects, Maps configuration, and entry points. GetIt and Injectable compose dependencies, while generated typed models keep serialization consistent.

Media is selected and compressed in Flutter before upload. PostgreSQL stores stable Firebase Storage paths rather than expiring download URLs, and the client resolves the current URL only when an image is rendered.

Backend support for the Flutter product

The Go API is split into independent business modules with domain types, application services, ports, and HTTP and PostgreSQL adapters. Global middleware handles request IDs, recovery, logging, CORS, rate limiting, authentication, and timeouts before requests enter a module.

PostgreSQL is the source of business data. The mobile application never connects to the database directly, and client-supplied identity is never accepted as a substitute for the authenticated Firebase token.

This boundary keeps security-sensitive rules outside the device while allowing Flutter to remain focused on interaction, state, navigation, and platform delivery.

Reservation integrity

Booking creation, appointment scheduling, availability, pricing, promotions, and status transitions are validated on the server. PostgreSQL transactions, row locking, and database constraints protect reservations from overlapping or inconsistent writes.

Reservation records keep historical snapshots of names, prices, discounts, and provider commission. Monetary values are stored as integer minor units so later business changes do not rewrite the financial meaning of an existing booking.

Realtime and delivery reliability

PostgreSQL notifications invalidate chat, dashboard, and earnings projections. The API recalculates an authorized snapshot and sends targeted server-sent events, while Flutter refreshes the relevant state instead of treating an event or push payload as authoritative business data.

Chat messages use client-generated identifiers for safe retries. Message creation, conversation state, unread state, and push outbox creation are committed together. Push delivery is processed separately with bounded retry behavior, so a temporary delivery failure does not roll back the user action.

What the project demonstrates

MultiBook demonstrates how I structure a substantial Flutter product beyond individual screens: clean architecture, predictable state ownership, navigation guards, typed API integration, platform services, session lifecycle, failure handling, and maintainable feature boundaries. The supporting backend demonstrates how I design the systems that protect and serve the mobile application without changing my primary focus as a Flutter developer.

Provider experience

Tools for running the business

A supporting operational view for managing bookings, appointments, availability, and earnings.

MultiBook provider dashboard with active appointments, earnings, rating, and trend chartMultiBook provider booking list with status filters and business selectionMultiBook appointment management sheet with customer, schedule, payment, and provider actionsMultiBook provider earnings dashboard with period and employee filtersMultiBook provider availability calendar with monthly and weekly views

Source code

Review the implementation

MultiBook is not publicly deployed, but the complete Flutter application and Go backend are available for direct review. The repositories show the feature structure, state management, API contracts, database schema, tests, and implementation decisions described in this case study.