event_app is the most ambitious of the consumer reference apps: a community platform that bundles events, social feed, ticketing, and group chat into one experience. Repo: /Users/imzee/projects/appmint_go/event_app/. Read COMMUNITY_PLATFORM.md in that folder for the product narrative.
If you want to see how four AppEngine modules compose into a single app, this is where to look.
What it uses
| Module | Endpoints |
|---|---|
| Profile | /profile/customer/signin, /profile/customer/signup, magic link |
| Events | /client/events/*, ticket purchase, QR, transfer |
| Community | /client/community/*, feed, posts, comments, reactions, follows, stories, notifications |
| Storefront | /storefront/products, Stripe intents (for ticket payments and merch) |
| Chat (community) | /community-chat Socket.IO namespace for group chat |
This combination is the highest-value example for non-trivial apps. Most production apps eventually bolt on more than one module; event_app shows the patterns for sharing one auth state, one HTTP client, and one socket connection across all of them.
Project layout
event_app/lib/
├── services/
│ ├── api_service.dart # Generic AppEngine wrapper
│ ├── http_client.dart # Singleton AppmintHttpClient
│ ├── community_chat_service.dart # /community-chat WebSocket
│ ├── activity_tracking_service.dart # User activity events
│ ├── client_info_service.dart # Device + app telemetry
│ ├── media_upload_service.dart # Multipart uploads
│ ├── stripe_service.dart # Payment intents
│ └── storage_service.dart
├── providers/ # Auth, Feed, Events, Cart
└── screens/ # Tabs for each module
Files to read first
lib/services/community_chat_service.dart— the cleanest WebSocket example in any reference app. ~200 lines, all stream-based. The chat recipe is derived from this.lib/services/api_service.dart— every REST call across events, community, and storefront in one file. Skim to see how multiple modules coexist.lib/services/activity_tracking_service.dart— fire-and-forget activity events (post viewed, event tapped, ticket scanned). Good model for any analytics-style "send and forget" client.COMMUNITY_PLATFORM.mdin the repo root — the product spec describing what the app does and why each module was chosen.
Patterns worth lifting
One socket per app, multiple namespaces
The chat gateway (/chat) and community-chat gateway (/community-chat) are separate Socket.IO namespaces but share the same JWT. The app maintains two singletons — one for support chat, one for community group chat — and lets them connect independently.
If you only need one of them, drop the other singleton. Both follow the same shape: stream-based callbacks, manual connect() once auth is loaded, disconnect() on sign-out.
Activity tracking as a side channel
// fire-and-forget
ActivityTrackingService().log(
type: 'post-viewed',
resourceId: postId,
metadata: {'feedPosition': index},
);
The service queues events in memory and flushes in batches every 30 seconds (or on app pause). The endpoint is /crm/activity/manage. This decouples UI code from analytics — call it freely without thinking about latency.
Multi-tab navigation with shared state
A BottomNavigationBar with five tabs (Feed, Events, Community, Tickets, Profile) all read the same AuthProvider. Each tab has its own provider:
FeedProviderfor community postsEventsProviderfor upcoming eventsCartProviderfor the merch shopping cartTicketsProviderfor purchased tickets
All five providers share the same appmintHttp singleton — there's exactly one HTTP client, one auth state, one socket. State sharing across tabs is cheap because the provider tree is rebuilt at the top.
Custom collections via /repository/*
Some app-specific data (e.g., event_app_settings) doesn't have a dedicated controller. The app uses the generic repository endpoints:
final settings = await appmintHttp.post('/repository/find/eventappsettings', body: {
'query': {},
'options': {'page': 1, 'pageSize': 1},
});
Read lib/services/api_service.dart for examples — any time you see /repository/find/..., that's a custom collection slot.
Architecture diagram (in words)
- Auth at the root → wires
AppmintHttpClientonce. - Five tabs → each pulls from a tab-specific provider.
- One WebSocket for
/community-chatgroup threads, one for/chatsupport. - Stripe lives as a flat service called from any tab that has a checkout (events tickets, storefront merch).
activity_tracking_serviceruns as a singleton, called from any screen.
What it doesn't do
- No biometrics — consumer expectation is password.
- No offline cache — feed and events refetch on tab focus.
- Limited push — the app uses email + in-app notifications, not FCM. Adding push is a near-term roadmap item.
Where to fork from
If you're building a community-first app (member portal, event platform, fan club):
- Copy
lib/services/{http_client,api_service,community_chat_service,activity_tracking_service}.dart. - Lift the bottom-nav scaffold and the per-tab provider pattern.
- Decide which AppEngine modules to keep — events without community is a perfectly valid trim.
Reference docs to pair with this example
- Community feed — the feed/posts/reactions flow.
- Events and tickets — the ticket purchase and QR flow.
- Chat with customer support — the WebSocket pattern.
- Browse products — the storefront for merch.