Documentation

reel_moment — camera rental

Walkthrough of the reel_moment Flutter app — a consumer rental and event-experience controller.

reel_moment is a consumer-facing camera rental app. End-users browse rental gear, book equipment for events, and use the app as a controller for booth/event experiences. The repo lives at /Users/imzee/projects/appmint_go/reel_moment/.

It's the simplest reference app — a customer storefront with a few specialized hardware-control surfaces — and the cleanest place to see the consumer auth + storefront pattern.

What it uses

ModuleEndpoints
Profile/profile/customer/signin, /profile/customer/signup
Storefront/storefront/products, /storefront/product/:id, /storefront/cart/*, /storefront/order/*
Stripe/storefront/stripe/intent, /storefront/checkout-cart
Repository/repository/find/:type (rental records)

No realtime, no push, no biometrics. Pure REST.

Project layout

reel_moment/lib/
├── config/             # API base URL, theme
├── models/             # Product, Order, Rental, User models
├── services/
│   ├── api_service.dart           # AppEngine REST wrapper
│   ├── http_client.dart           # Singleton AppmintHttpClient
│   ├── storage_service.dart       # JWT in flutter_secure_storage
│   ├── stripe_service.dart        # Stripe payment intents
│   ├── camera_service.dart        # Hardware control (booth-side)
│   ├── canon_camera_service.dart  # Canon SDK bridge
│   ├── gopro_camera_service.dart  # GoPro REST/BLE
│   ├── face_detection_service.dart
│   ├── effects_service.dart
│   └── sharing_service.dart
├── providers/
└── screens/

The services/ folder shows the split clearly: a generic AppEngine layer (api_service, http_client, storage_service) and a hardware/effects layer for the booth controller. Most rental apps will only need the AppEngine layer.

Files to read first

If you're forking the app, start with these:

  • lib/services/http_client.dart — the singleton HTTP client, identical in structure to the one canonicalized in client-pattern.
  • lib/services/api_service.dart — every API call wrapped in a typed method. Browse this to see how the storefront, rental, and profile endpoints are stitched together.
  • lib/services/storage_service.dartflutter_secure_storage for tokens, shared_preferences for everything else. The pattern that's repeated in every other app.
  • lib/services/stripe_service.dart + the _mobile.dart and _stub.dart siblings — platform-conditional Stripe integration. The stub is for web/desktop where Stripe SDK isn't available.

Patterns worth lifting

Conditional service implementations

The Stripe service is split three ways:

services/
├── stripe_service.dart        # Re-exports based on platform
├── stripe_service_mobile.dart # Real implementation
└── stripe_service_stub.dart   # No-op for web/desktop

The exporter uses dart.library.io to pick:

export 'stripe_service_stub.dart'
    if (dart.library.io) 'stripe_service_mobile.dart';

This lets you compile the same source tree for web (where Stripe Mobile SDK doesn't link) and mobile (where it does). Use this pattern for any plugin without web support: location, biometrics, native cameras.

Image picker for return verification

Renters take photos of returned equipment to document condition. The pattern uses image_picker plus a plain MultipartRequest against the file upload endpoint:

final picked = await ImagePicker().pickImage(source: ImageSource.camera);
final request = http.MultipartRequest(
  'POST',
  Uri.parse('${appmintHttp.baseUrl}/storefront/order/$orderNumber/files'),
);
request.headers.addAll(appmintHttp.getAuthHeaders());
request.files.add(await http.MultipartFile.fromPath('file', picked!.path));
final response = await request.send();

Note appmintHttp.getAuthHeaders() — the public method on the singleton — so you don't have to re-implement auth header building for multipart.

What it doesn't do

  • No biometrics — sign-in is password only every cold start (acceptable for low-friction rental flow).
  • No offline cache — products and orders refetch on every screen open.
  • No push notifications — pickup reminders are sent via email only.
  • No WebSocket — order status updates land via pull-to-refresh.

For a richer pattern (offline + push + biometrics), look at appmint_mobile.

Where to fork from

If you're building a rental or single-vertical consumer app:

  1. Copy lib/config, lib/services/{http_client,api_service,storage_service}.dart, and lib/providers/auth_provider.dart into a new project.
  2. Replace the rental-specific models and screens with your domain.
  3. Keep the Stripe service split if you'll ever target web.

The total surface is about 2,000 lines of plumbing — most of the rest is product/screen code you'll rewrite anyway.

Reference docs to pair with this example