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
| Module | Endpoints |
|---|---|
| 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.dart—flutter_secure_storagefor tokens,shared_preferencesfor everything else. The pattern that's repeated in every other app.lib/services/stripe_service.dart+ the_mobile.dartand_stub.dartsiblings — 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:
- Copy
lib/config,lib/services/{http_client,api_service,storage_service}.dart, andlib/providers/auth_provider.dartinto a new project. - Replace the rental-specific models and screens with your domain.
- 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
- Client pattern — the
AppmintHttpClientshape. - Auth —
/profile/customer/signinflow. - Browse products — the storefront list pattern.
- Checkout with Stripe — the payment intent flow.