nomadcode/apps/client/README.md

7.2 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, 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) in pubspec.yaml, while maintaining the same directory layout.

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/MattermostPushClient interface, MattermostPushPluginClient adapter (the only production reference to NexoMessagingPlugin.instance), MattermostPushHostIntegration (initialize + auth handoff + navigation callbacks), and MattermostAuthService.
  • integrations/proto_socket/ProtoSocketEndpointConfig and ProtoSocketLifecycle facade over the local proto_socket Dart 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 standard Firebase.initializeApp() call in Dart main.
  • Mattermost Authentication: Handles login and session lifecycles, and passes the user authentication token and server signing key through the MattermostPushClient boundary. The production MattermostPushPluginClient adapter owns the plugin singleton calls. Local smoke credentials may be provided as ignored assets/mattermost_credentials.json.
  • Navigation Callbacks: Registers standard Flutter navigation callbacks onNavigateToChannel and onNavigateToThread to handle workspace channel and CRT thread routing upon user interaction.
  • FCM Token Sync: Listens to device token registrations via onDeviceTokenReady and 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 the apps/client standard. Align folder structures under src/app, src/features, and src/integrations. Do not clone NomadCode product-specific screens—only the integration and bootstrap skeletons.
  • ../alt: Retain ALT-specific Riverpod-based dependency graph and go_router for app routing. However, extract external adapters into lib/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:

  1. Dart Package Name: Rename nomadcode_app to your target app package identifier in pubspec.yaml.
  2. 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).
  3. Firebase Configuration: Replace google-services.json (Android) and GoogleService-Info.plist (iOS) with target project project credentials.
  4. Endpoint Defaults: Update ProtoSocketEndpointConfig initialization defaults in environment configurations to route to your target backends.
  5. 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