This commit restructures the monorepo to improve organization, maintainability, and scalability. The changes include: - Moving mobile apps from `mobile-apps/` to `apps/mobile-*`. - Moving the web dashboard from `admin-web/` and `frontend-web/` to `apps/web-dashboard/`. - Moving Firebase-related files to the root `firebase/` directory. - Adding a `.geminiignore` file to exclude unnecessary files from Gemini analysis. - Updating `.gitignore` to reflect the new structure and exclude sensitive files. - Updating `codemagic.yaml` to reflect the new app locations. - Adding a `make help` command to the root directory. - Adding a `make install-git-hooks` command to install git hooks. - Adding a `docs/02-codemagic-env-vars.md` file to document Codemagic environment variables. - Adding a `docs/03-contributing.md` file to document contribution guidelines. - Adding prototype placeholders to the internal launchpad. - Updating the `README.md` file to reflect the new structure and provide updated instructions. These changes improve the overall structure of the monorepo and make it easier to develop, maintain, and scale the KROW Workforce platform.
6.1 KiB
Krow Mobile Staff App - Architecture Document
A. Introduction
This document outlines the architecture of the Krow Mobile Staff App, a Flutter application designed to connect staff with job opportunities. The app provides features for staff to manage their profiles, view and apply for shifts, track earnings, and complete necessary paperwork.
The core purpose of the app is to streamline the process of finding and managing temporary work, providing a seamless experience for staff from onboarding to payment.
B. Full Architecture Overview
The application follows a Clean Architecture pattern, separating concerns into three main layers: Presentation, Domain, and Data. This layered approach promotes a separation of concerns, making the codebase more maintainable, scalable, and testable.
-
Presentation Layer: This layer is responsible for the UI and user interaction. It consists of widgets, screens, and Blocs that manage the UI state. The Presentation Layer depends on the Domain Layer to execute business logic.
-
Domain Layer: This layer contains the core business logic of the application. It consists of use cases (interactors), entities (business objects), and repository interfaces. The Domain Layer is independent of the other layers.
-
Data Layer: This layer is responsible for data retrieval and storage. It consists of repository implementations, data sources (API clients, local database), and data transfer objects (DTOs). The Data Layer depends on the Domain Layer and implements the repository interfaces defined in it.
Integration Points
- UI → Domain: The UI (e.g., a button press) triggers a method in a Bloc. The Bloc then calls a use case in the Domain Layer to execute the business logic.
- Domain → Data: The use case calls a method on a repository interface.
- Data → External: The repository implementation, located in the Data Layer, communicates with external data sources (GraphQL API, Firebase, local storage) to retrieve or store data.
C. Backend Architecture
The backend is built on a combination of a GraphQL server and Firebase services.
-
GraphQL Server: The primary endpoint for the Flutter app. It handles most of the business logic and data aggregation. The server is responsible for communicating with Firebase services to fulfill requests.
-
Firebase Services:
- Firebase Auth: Used for user authentication, primarily with phone number verification.
- Firebase Firestore: The main database for storing application data, such as user profiles, shifts, and earnings.
- Firebase Storage: Used for storing user-generated content, such as profile avatars.
- Firebase Cloud Messaging: Used for sending push notifications to users.
- Firebase Remote Config: Used for remotely configuring app parameters.
API Flow
- Flutter App to GraphQL: The Flutter app sends GraphQL queries and mutations to the GraphQL server.
- GraphQL to Firebase: The GraphQL server resolves these operations by interacting with Firebase services. For example, a
getShiftsquery will fetch data from Firestore, and anupdateStaffPersonalInfoWithAvatarmutation will update a document in Firestore and upload a file to Firebase Storage. - Response Flow: The data flows back from Firebase to the GraphQL server, which then sends it back to the Flutter app.
D. API Layer
The API layer is responsible for all communication with the backend.
-
GraphQL Operations: The app uses the
graphql_flutterpackage to interact with the GraphQL server. Queries, mutations, and subscriptions are defined in.dartfiles within each feature'sdatadirectory. -
API Error Handling: The
ApiClientclass is responsible for handling API errors. It catches exceptions and returns aFailureobject, which is then handled by the Bloc in the Presentation Layer to show an appropriate error message to the user. -
Caching: The
graphql_flutterclient provides caching capabilities. The app uses aHiveStoreto cache GraphQL responses, reducing the number of network requests and improving performance. -
Parsing: JSON responses from the API are parsed into Dart objects using the
json_serializablepackage.
E. State Management
The application uses the Bloc library for state management.
-
Why Bloc? Bloc is a predictable state management library that helps to separate business logic from the UI. It enforces a unidirectional data flow, making the app's state changes predictable and easier to debug.
-
State Flow:
- UI Event: The UI dispatches an event to the Bloc.
- Bloc Logic: The Bloc receives the event, executes the necessary business logic (often by calling a use case), and emits a new state.
- UI Update: The UI listens to the Bloc's state changes and rebuilds itself to reflect the new state.
-
Integration with API Layer: Blocs interact with the API layer through use cases. When a Bloc needs to fetch data from the backend, it calls a use case, which in turn calls a repository that communicates with the API.
F. Use-Case Flows
User Authentication
- UI: The user enters their phone number.
- Logic: The
AuthBlocsends the phone number to Firebase Auth for verification. - Backend: Firebase Auth sends a verification code to the user's phone.
- UI: The user enters the verification code.
- Logic: The
AuthBlocverifies the code with Firebase Auth. - Backend: Firebase Auth returns an auth token.
- Logic: The app sends the auth token to the GraphQL server to get the user's profile.
- Response: The GraphQL server returns the user's data, and the app navigates to the home screen.
Shift Management
- UI: The user navigates to the shifts screen.
- Logic: The
ShiftsBlocrequests a list of shifts. - Backend: The use case calls the
ShiftsRepository, which sends agetShiftsquery to the GraphQL server. The server fetches the shifts from Firestore. - Response: The GraphQL server returns the list of shifts, which is then displayed on the UI.