8 KiB
nomadcode-app
The Flutter-first NomadCode client application.
Client Module Standard
The Flutter host application in this monorepo is standardized under apps/client/. This directory serves as the reference architecture for other projects (such as ../iop and ../alt) to replicate.
Directory Layout
lib/src/app/: Root application routing, workbench shell, bootstrap settings (bootstrap.dart), global configurations, and state setup.lib/src/features/: Feature-specific UI surfaces, business logic, and local UI state. Keep layout decoupled from shared integration protocols.lib/src/integrations/: Adapters and lifecycle hooks for external system boundaries. Any connection initialization or platform-specific service logic should reside here under strict interfaces.
Naming Conventions
- Flutter Host Path: Always kept as
apps/client/to act as the primary client skeleton. - Dart Package Name: Standardized as
nomadcode_app. When cloning, this package name can be customized to match target project identities (e.g.iop_client_app,alt_client_app) inpubspec.yaml, while maintaining the same directory layout.
Workbench Shell
lib/src/app/nomadcode_workbench_shell.dart owns the current NomadCode client shell. It provides a top titlebar, a right-side activity rail, center content switching, and an Agent dock panel attached to the right rail. The rail keeps product/workflow placeholder icons near the top and the IOP entry at the bottom.
The Agent dock uses the sibling agent_shell package as a product-neutral chat/agent surface. Workflow, Web Context, and optional IOP management areas are mounted as center content sections. IOP-specific UI should be composed through an IOP-owned package or widget boundary via the optional iopContent slot rather than copied into NomadCode client code.
WorkspaceHomePage can hide its own app bar through showAppBar: false when it is mounted inside the workbench shell.
Bootstrap
NomadCode features a standardized, platform-safe bootstrap layer in lib/src/app/bootstrap.dart:
- Common Initialization Path:
bootstrapNomadCodeClient()performs synchronous preparation, setups UI configurations (e.g., fullscreen system overlays), and initializes Firebase + Mattermost push notification boundaries. - Platform-Specific Guard: Native modules and background tasks (such as Firebase Messaging background handlers) are cleanly guarded inside integration-specific or native layers, preventing background crashes or initialization collision.
- No-Op Defaults: External transport components (such as the proto-socket lifecycle engine) initialize with safe no-op adapters by default to guarantee bootstrap safety.
Platform Targets
We prioritize and validate two primary platforms in this milestone, while ensuring others can be added seamlessly:
- Web & Android (Primary Targets): Fully validated in the main bootstrap configuration. Local notification integration and web socket configurations are verified to build and bootstrap without compilation errors.
- iOS (Future Expansion): iOS is treated as a first-class citizen using the same Dart APIs and integration facade boundaries (
MattermostPushClient,ProtoSocketLifecycle). Native iOS APNS and notification delegate handlers can be wired later into the same Dart interfaces without modifying the core bootstrap logic.
Integration Boundaries
apps/client/lib/src/integrations/ groups all external-system adapters behind small Dart interfaces:
integrations/mattermost/—MattermostPushClientinterface,MattermostPushPluginClientadapter (the only production reference toNexoMessagingPlugin.instance),MattermostPushHostIntegration(initialize + auth handoff + navigation callbacks), andMattermostAuthService.integrations/proto_socket/—ProtoSocketEndpointConfigandProtoSocketLifecyclefacade over the localproto_socketDart path dependency. Bootstrap does not auto-connect; enabling and wiring a real connector are deferred to the next milestone.
For detailed integration boundaries, platform targets, and clone handoff guidelines, see push-notification-todo.md.
Mattermost Push Notification Integration
Mattermost push notification delivery is implemented via the local nexo_messaging path dependency at ../nexo/packages/messaging_flutter.
Architecture & Responsibility Split
To maintain a clean and maintainable codebase, the responsibilities are split between the host application and the plugin as follows:
Host Application (apps/client) Responsibilities:
- Firebase Configuration: Contains the standard Firebase configuration files (
android/app/google-services.json) and performs the standardFirebase.initializeApp()call in Dart main. - Mattermost Authentication: Handles login and session lifecycles, and passes the user authentication token and server signing key through the
MattermostPushClientboundary. The productionMattermostPushPluginClientadapter owns the plugin singleton calls. Local smoke credentials may be provided as ignoredassets/mattermost_credentials.json. - Navigation Callbacks: Registers standard Flutter navigation callbacks
onNavigateToChannelandonNavigateToThreadto handle workspace channel and CRT thread routing upon user interaction. - FCM Token Sync: Listens to device token registrations via
onDeviceTokenReadyand registers the token with the Mattermost server.
Nexo Messaging Plugin (nexo_messaging) Responsibilities:
- Native Android FCM Service: Intercepts background/foreground FCM notifications securely via a custom Kotlin FCM service.
- Signature Verification: Validates incoming push payload signatures against stored public signing keys (using
JJWT). - System Notification Builder: Displays structured notifications with local avatar caches, thread summaries, and action buttons.
- Inline Reply / Dismiss Actions: Receives native background actions, records responses in a Room database, and forwards replies/ACKs directly to the Mattermost API via custom OkHttp adapters.
Cloning & Handoff Checklist
For sibling repositories (../iop and ../alt) aiming to align with this standard structure:
Sibling Specific Alignment Guidelines:
../iop: Avoid emphasizing legacy Portal naming conventions. Reorganize/rename legacy mobile paths to theapps/clientstandard. Align folder structures undersrc/app,src/features, andsrc/integrations. Do not clone NomadCode product-specific screens—only the integration and bootstrap skeletons.../alt: Retain ALT-specific Riverpod-based dependency graph andgo_routerfor app routing. However, extract external adapters intolib/src/integrations/matching the common Dart facade interfaces (MattermostPushClient,ProtoSocketLifecycle) to align the bootstrap pipeline.
Common Replacement Checklist:
When cloning this host template into a new environment, replace the following values:
- Dart Package Name: Rename
nomadcode_appto your target app package identifier inpubspec.yaml. - Display & App Naming: Adjust launcher configurations, bundle identifiers, and target product names in native assets (
android/app/src/main/AndroidManifest.xml,ios/Runner/Info.plist). - Firebase Configuration: Replace
google-services.json(Android) andGoogleService-Info.plist(iOS) with target project project credentials. - Endpoint Defaults: Update
ProtoSocketEndpointConfiginitialization defaults in environment configurations to route to your target backends. - Mattermost Server Configurations: Update server URLs, authentications, and asymmetrical public keys matching the target deployment environment.
Verification
To ensure code stability and structure correctness, run the following verification checks within this directory:
- Unit Tests:
flutter test - Static Analysis:
flutter analyze --no-fatal-infos - Web Build Validation:
flutter build web