{"id":27455575,"url":"https://github.com/aadimanchekar/fleet","last_synced_at":"2026-04-08T20:36:33.966Z","repository":{"id":284804406,"uuid":"955074494","full_name":"AadiManchekar/Fleet","owner":"AadiManchekar","description":"Fleet is a project aimed at developing a cab aggregator app while documenting key technical decisions.","archived":false,"fork":false,"pushed_at":"2025-05-25T09:43:10.000Z","size":6566,"stargazers_count":0,"open_issues_count":1,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-05-25T10:36:51.384Z","etag":null,"topics":["java","kafka","maven","postgresql","redis","spring-boot","system-design","uber-clone"],"latest_commit_sha":null,"homepage":"","language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/AadiManchekar.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-03-26T04:17:15.000Z","updated_at":"2025-05-17T19:29:29.000Z","dependencies_parsed_at":"2025-05-25T10:28:36.128Z","dependency_job_id":"24401be5-c7c6-458d-9f10-ce80cee17383","html_url":"https://github.com/AadiManchekar/Fleet","commit_stats":null,"previous_names":["aadimanchekar/fleet"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AadiManchekar%2FFleet","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AadiManchekar%2FFleet/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AadiManchekar%2FFleet/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AadiManchekar%2FFleet/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/AadiManchekar","download_url":"https://codeload.github.com/AadiManchekar/Fleet/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AadiManchekar%2FFleet/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":259114444,"owners_count":22807243,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["java","kafka","maven","postgresql","redis","spring-boot","system-design","uber-clone"],"created_at":"2025-04-15T16:44:08.939Z","updated_at":"2026-04-08T20:36:33.933Z","avatar_url":"https://github.com/AadiManchekar.png","language":"Shell","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Fleet 🚖\nFleet is my attempt at building a functional and scalable cab aggregator application while honing my problem-solving and decision-making abilities. Every technical and architectural choice comes with trade-offs, and I aim to document each one, providing insights into the challenges and solutions involved in building such a platform. This project is a continuous work in progress, evolving as I acquire new knowledge and skills.\n\n---\n\n## Why Fleet Uses GPL 3.0 📜\nFleet is licensed under GPL 3.0 to promote open collaboration and ensure that any modifications or improvements made by others remain open-source. This aligns with the project's goal of learning and sharing knowledge while fostering a community-driven development approach.\n\n---\n\n## Requirements 📝\n\n### Functional Requirements\nFleet must provide the following core functionalities to ensure a seamless user experience:\n- **Real-Time Driver Location Tracking**: Continuously track and update driver locations.\n- **Ride Booking**: Allow users to book rides, view ride details and ride status.\n\n\n### Non-Functional Requirements\nTo ensure the system is robust, scalable, and maintainable, the following non-functional requirements must be met:\n- **High Performance**:\n  - Low response time for API calls.\n  - Low latency for real-time updates.\n  - High throughput to handle multiple concurrent requests.\n- **Scalability**:\n  - Support horizontal scaling to handle increased traffic.\n  - Database design must support partitioning and sharding for efficient data management.\n- **Maintainability**:\n  - Follow modular design principles for easier updates and debugging.\n  - Ensure clean architecture and clean code practices.\n- **Monitoring and Logging**:\n  - Log all critical events for debugging.\n  - Use tools like OpenTelemetry for real-time monitoring and observability.\n\n---\n\n## Architecture 🏗️\n\n### Microservices\n\n#### 1. Customer Communication Service\n**Purpose:** Facilitates real-time, bi-directional communication by maintaining connections with customers.\n**Techstack:** Spring Boot, gRPC  \n**Infra:** None  \n**Key Decisions:**\n- Chose gRPC over REST to boost performance.  \n- Enables bi-directional streaming for efficient, real-time data exchange.\n\n#### 2. Ride Aggregator Service\n**Purpose:** Acts as an aggregator service, `Customer Communication Service` will call `ride-aggregator-service` which inturns coordinates with other microservices to fullfill the request.  \n**Techstack:** Spring Boot, gRPC  \n**Infra:** Kafka  \n**Key Decisions:**\n- Utilizes Kafka for asynchronous processing, except when interacting with the `ride-booking-service` where immediate database updates via gRPC are essential.  \n- Simplifies the client-side by consolidating multiple service calls into a single API endpoint.\n\n#### 3. Ride Booking Service\n**Purpose:** Manages ride status updates and maintains persistent ride data.  \n**Techstack:** Spring Boot, gRPC  \n**Infra:** PostgreSQL  \n**Key Decisions:**\n- Utilizes PostgreSQL to persist ride details\n\n#### 4. Driver Matching Service\n**Purpose:** Fetches the 10 closest drivers for a ride request.  \n**Techstack:** Spring Boot  \n**Infra:** Redis  \n**Key Decisions:**\n- Utilizes Redis for quick access to driver locations.\n\n#### 5. Driver Connection Service\n**Purpose:** Maintains connections with drivers and facilitates real-time communication.  \n**Techstack:** gRPC, QUIC  \n**Infra:** Kafka  \n**Key Decisions:**\n- Uses NLB (Layer 4) instead of ALB for persistent low-latency connections.\n- Uses gRPC for ride acceptance/decline and QUIC for efficient location updates.\n- Offloads incoming location updates to Kafka for asynchronous processing.\n\n#### 6. Driver Location Service\n**Purpose:** Listens to driver location updates and persists them in Redis.  \n**Techstack:** Spring Boot, Kafka, Redis  \n**Infra:** Redis, Kafka  \n**Key Decisions:**\n- Utilizes Kafka for scalable ingestion of location updates.\n- Utilizes Redis to store frequently changing location data efficiently.\n\n\n### Infrastructure Components\n\n### Diagrams\n\n### High-Level Design (HLD)\n\n![Fleet HLD v5](docs/architecture/v5/images/HLD.png)\n\n*Figure 1: High-Level Design for Fleet*\n\n\n### Clean Code Architecture\n\n![Fleet Clean Code Architecture v5](docs/architecture/v5/images/Clean-Code-Architecture.png)\n\n*Figure 2: Clean Code Architecture for Fleet*\n\n### Microservice Design Decisions\nThis section outlines the key decisions made for each microservice in the Fleet application:\n\n#### 1. Why Event-Driven Architecture?\n**Pros:**\n- Decouples entire system into small microservices.\n- Highly scalable.\n- Fault tolerance.\n- Reduces synchronous dependencies.\n\n**Cons:**\n- Operational complexity.\n\n**Final Decision:**\nFleet heavily relies on real-time updates and scale-out capabilities, making event-driven architecture the optimal choice.\n\n\n#### 2. Why Amazon EKS?\n**Pros:**\n- Managed Kubernetes service reduces operational overhead.\n- Seamless integration with AWS ecosystem (ALB, NLB, etc.).\n- Autoscaling and high availability built-in.\n\n**Cons:**\n- Requires knowledge of AWS ecosystem.\n- Vendor lockdown.\n\n**Final Decision:**\nEKS provides a fully managed Kubernetes environment with enterprise-level scalability, making it ideal for our microservices.\n\n\n\u003cdel\u003e\n\n#### 3. Why Customer-Facing Load Balancer is ALB, Not NLB?\n**Pros of ALB:**\n- Supports HTTP/2 and gRPC routing.\n- Provides TLS termination, simplifying microservices.\n\n**Cons of NLB:**\n- Lacks HTTP routing capabilities.\n- Requires backend services to manage TLS termination.\n\n**Final Decision:**\nALB is used for customer-facing traffic as it supports TLS termination and HTTP-based routing efficiently.\n\n\u003c/del\u003e\n\n**-\u003e Customer-Facing Load Balancer is now NLB, as AWS NLB supports TLS termination**\n\n\n\u003cdel\u003e\n\n#### 4. TLS Termination at ALB (Not API Gateway)?\n**Pros of ALB TLS Termination:**\n- Offloads TLS management, reducing API Gateway load.\n- Simplifies client integration as only ALB needs certificates.\n\n**Cons:**\n\n\n**Final Decision:**\nALB handles TLS termination to simplify infrastructure and offload certificate management from the backend.\n\n\u003c/del\u003e\n\n**-\u003e Reduced sope of the project. Hence, API Gateway is removed**\n\n\n\u003cdel\u003e\n\n#### 5. Why API Gateway?\n**Pros:**\n- Future-proofing for authentication, rate limiting, and caching.\n- Protocol translation for improved efficiency.\n\n**Cons:**\n- Adds an extra hop, increasing latency.\n\n**Final Decision:**\nAPI Gateway provides flexibility and scalability, making it essential for managing client-facing requests.\n\n\u003c/del\u003e\n\n**-\u003e Reduced sope of the project. Hence, API Gateway is removed**\n\n\n#### 6. Why Aggregator Service?\n**Pros:**\n- A single API call is required instead of calling individual microservices.\n- Handles failures.\n\n**Cons:**\n- Adds an extra layer of processing.\n\n**Final Decision:**\nAggregator service enables a more maintainable, modular architecture and helps to handle failures if a microservice fails to respond.\n\n\n\u003cdel\u003e\n\n#### 7. Why API Gateway, Aggregator, and Ride Booking Service Use gRPC Instead of Kafka?\n**Pros**\n- Low-latency, high-performance communication.\n- Synchronous request-response handling for ride bookings.\n\n**Cons**\n\n**Final Decision:**\ngRPC is used for request-response flows, while Kafka is used for event-driven processes.\n\n\u003c/del\u003e\n\n**-\u003e Reduced sope of the project. Hence, API Gateway is removed. Driver communication service uses gRPC to co-ordinate with Aggregator service due to Low-latency, high-performance,  Synchronous request-response handling needs.**\n\n\n#### 8. Why Redis for Storing Frequent Driver Locations?\n**Pros:**\n- Low-latency data access.\n- Supports high-throughput reads and writes.\n\n**Cons:**\n\n**Final Decision:**\nRedis is ideal for frequently changing data like driver locations due to its speed and efficiency.\n\n\n#### 9. Why PostgreSQL for Customer, Driver, and Ride Details?\n**Pros:**\n- ACID compliance ensures data consistency.\n- Optimal to storage relational data.\n- Supports complex queries efficiently.\n\n**Cons:**\n- Requires careful schema design and indexing to maintain performance at scale.\n- Less flexible for handling unstructured or rapidly evolving data models.\n\n**Final Decision:**\nPostgreSQL offers full ACID compliance, robust community support, and is one of the most reliable and well-established relational databases available.\n\n\n#### 10. Why We Ditch WebSockets and Use gRPC + QUIC?\n**Pros of gRPC + QUIC:**\n- gRPC (ride accept/decline) ensures low-latency bidirectional communication. TCP based so gurantees message delivery.\n- QUIC (location updates) is optimized for real-time streaming over UDP. its okay if a packet gets lost.\n\n**Cons of WebSockets:**\n- Higher overhead compared to QUIC.\n- Less efficient for mobile networks.\n\n**Final Decision:**\ngRPC + QUIC provides the best combination of efficiency and performance for real-time communication.\n\n\n#### 11. Why NLB for Driver Connections Instead of ALB?\n**Pros of NLB:**\n- Lower latency, better suited for persistent connections.\n- Supports both TCP and UDP (required for gRPC and QUIC).\n- Supports TLS termination.\n\n**Cons of ALB:**\n- Poor support for long-lived connections.\n\n**Final Decision:**\nNLB is used for driver connections to ensure low-latency, persistent communication channels.\n\n\n#### 12. Why Customer Communication Service Uses gRPC \n**Pros of gRPC for Bidirectional Communication:**\n- Enables low-latency, high-performance, bidirectional streaming ideal for real-time customer interactions.\n- Provides efficient and reliable message exchange between clients and the service.\n\n**Final Decision:**\nUsing gRPC for bidirectional communication ensures robust, real-time, fast \u0026 reliable communication\n\n---\n\n## Challenges Faced 🧗\nBuilding Fleet came with its own set of challenges, which provided valuable learning opportunities:\n\n1. **Docker Compose Command: Why Only the First Arg Runs**  \nWhat i wrote (Did not work)\n```yaml\ncommand: chmod +x /vault/workflow-vault.sh \u0026\u0026 /vault/workflow-vault.sh\n```\nDocker Compose interpreted this as an exec form.\nSo, in the container, this was equivalent to:\n```json\n\"Args\": [\n  \"chmod\",\n  \"+x\",\n  \"/vault/workflow-vault.sh\"\n]\n```\nInorder to solve it, i re-wrote it as\n```yaml\ncommand: [\"/bin/sh\", \"-c\", \"chmod +x /vault/workflow-vault.sh \u0026\u0026 /vault/workflow-vault.sh\"]\n```\n- **Exec Form vs Shell Form:**  \n  - When you use `command:` as a plain string or YAML list, Docker Compose uses the exec form, which does **not** invoke a shell. It splits the command by spaces and only runs the first command with the rest as arguments. Shell features like `\u0026\u0026` are ignored.\n  - When you explicitly use `/bin/sh -c \"...\"`, Docker runs the command through a shell. The shell understands `\u0026\u0026`, so all chained commands are executed in sequence.  \n\n2. **Line Endings Issue (CRLF vs LF)**  \nWhile working with the `init-vault.sh` script, I encountered an issue where the script was present in the container but failed to execute with the error:  \n`/bin/sh: /vault/init-vault.sh: not found`.  \n\n- **Root Cause Analysis (RCA):**  \nThe issue was caused by the script having Windows-style line endings (`CRLF`) instead of Unix-style line endings (`LF`). Linux-based containers require Unix-style line endings, and the presence of `CRLF` made the script unreadable or unexecutable.\n\n- To resolve the issue, I converted the line endings to `LF` using the following steps:\n  - I used **vscode** as it provides an option to change line endings.\n  - **You can also use `dos2unix` Command:**\n    ```bash\n    dos2unix ./vault/init-vault.sh\n    ```  \n\n\n3. **Kafka-UI Healthcheck:**  \nI initially wanted to use `curl` to check the `/actuator/health` endpoint, but the official `provectuslabs/kafka-ui` image does not include `curl` and installing it at runtime failed due to lack of permissions (`apk add --no-cache curl` resulted in a \"Permission denied\" error).  \nTo keep the image unchanged and avoid building a custom image, I switched to using `wget`, which is available by default. The healthcheck looks like this:\n  ```yaml\n  healthcheck:\n    test: [\"CMD-SHELL\",\n      \"wget -qO- http://localhost:8080/actuator/health \\\n        | grep -q '\\\"status\\\":\\\"UP\\\"'\"]\n    interval: 30s\n    timeout: 10s\n    retries: 3\n  ```\n  **How it works:**  \n  - `wget -qO- http://localhost:8080/actuator/health` fetches the health endpoint and outputs the response to stdout.\n  - `grep -q '\"status\":\"UP\"'` searches for the string `\"status\":\"UP\"` in the response.\n  - If `grep` finds the string, it exits with code `0` (success), signaling the container is healthy.\n  - If not found, `grep` exits with code `1` (failure), marking the container as unhealthy.   \n\n\n4. **Alpine Image and gRPC Protoc Plugin Compatibility**\nWhile building the application Docker image, I initially used an Alpine-based Maven image (`maven:3.9.9-eclipse-temurin-21-alpine`) for its small size and efficiency. However, during the `mvn package` step, I encountered the following error:\n\n```\nPROTOC FAILED: /app/dummy-child-module/target/protoc-plugins/protoc-gen-grpc-java-1.70.0-linux-x86_64.exe: program not found or is not executable\n```\n\n- **Root Cause Analysis (RCA):**  \nUpon investigation, I discovered that the gRPC Java protoc plugin is compiled against `glibc` (GNU C Library), while Alpine Linux uses `musl libc`. This incompatibility prevents the plugin from running on Alpine-based images.\n\n- **Solution:**  \nTo resolve this, I switched the build stage base image from `maven:3.9.9-eclipse-temurin-21-alpine` (Alpine/musl) to `maven:3.9.9-eclipse-temurin-21` (Debian/glibc). This change allowed the gRPC protoc plugin to execute successfully during the build process.   \n\n---\n\n## Learnings Along the Way 📚\nDeveloping Fleet has been a rewarding experience, offering numerous insights and learnings:\n\n1. **Formatting** was a big challenge and wanted to maintain consistent formatting. Found **Spotless Maven Plugin** that solves most of the issues, and we can specify formatting for various types of languages.\n  - Links referred:\n    - [Baeldung: Spotless Maven Plugin](https://www.baeldung.com/java-maven-spotless-plugin)\n    - [GitHub: Spotless Maven Plugin](https://github.com/diffplug/spotless/blob/main/plugin-maven/README.md)\n\n2. **gRPC** was chosen for its high-performance, low-latency communication capabilities. It supports bidirectional streaming and is well-suited for real-time systems like Fleet. Implementing gRPC required understanding protocol buffers and setting up efficient service definitions. It significantly improved the system's responsiveness and scalability.\n  - Links referred:\n    - [gRPC vs REST](https://blog.postman.com/grpc-vs-rest/)\n    - [gRPC Official Documentation](https://grpc.io/docs/)\n    - [Protocol Buffers Documentation](https://protobuf.dev/)\n\n3. **QUIC** was selected for its modern, low-latency, and reliable transport protocol, especially suited for real-time streaming and mobile networks. QUIC operates over UDP, providing faster connection establishment, improved congestion control, and better performance in lossy network conditions compared to traditional TCP. This choice significantly enhanced the system's ability to deliver real-time data with minimal delay, even on unreliable networks.\n  - Links referred:\n    - [The QUIC Transport Protocol: Design and Internet-Scale Deployment (Google Research)](https://research.google/pubs/the-quic-transport-protocol-design-and-internet-scale-deployment/)\n    - [Cloudflare Blog: The Road to QUIC](https://blog.cloudflare.com/the-road-to-quic/)\n\n4. **PostgreSQL** was chosen for its robust ACID compliance, strong support for relational data, and mature ecosystem. PostgreSQL excels at handling complex queries and ensures data consistency. Its reliability and extensive community support make it a solid choice.\n  - Links referred:\n    - [Fundamentals of Database Engineering](https://www.udemy.com/course/database-engines-crash-course/)\n  \n5. **Formatting Protobuf Files** Formatting protobuf files with maven-spotless plugin was challenging as it required the `buf` CLI path to be provided. The main issue arose when running this setup in a cross-platform environment, as Maven does not support conditional logic like `if-else` clauses. One workaround would be Maven profiles, but its unnecessary complexity. Instead, I chose to use **pre-commit hooks**, which offered several advantages:\n  - Ability to format Protobuf files.\n  - Additional features like secret detection, syntax correction, and validation for YAML and JSON files.\n\n  - Links referred:\n    - https://github.com/diffplug/spotless/blob/main/plugin-maven/README.md#protobuf\n    - https://pre-commit.com/#usage\n    - https://pre-commit.com/#plugins\n\n6. **Protobuf Design Best Practices**  Designing Protobuf files for Fleet involved structuring all `.proto` files under the `proto/` directory, with subdirectories like `common/`, `customer/`, and `driver/` to reflect service boundaries and ownership. To ensure maintainability, compatibility, and clarity.\n  - Adopted clear and consistent naming conventions for messages, fields, and enums across all proto files.\n  - Organized proto files into logical packages and directories (e.g., `proto/common/`, `proto/customer/`, `proto/driver/`) to mirror microservice domains.\n  - Always used fully qualified names for cross-package references (e.g., `fleet.proto.common.Location`).\n  - Added descriptive comments for every message, field, and enum to improve documentation and readability.\n  - Kept proto files small and focused, splitting larger definitions into multiple files within the appropriate subdirectory.\n  - Leveraged linting and formatting tools (like `buf` and pre-commit hooks) to enforce style and catch errors early.\n\n  - Links referred:\n    - https://buf.build/docs/format/style/\n    - https://protobuf.dev/best-practices/dos-donts/  \n\n7. **Vault**  \nVault is used to securely store both static and dynamic secrets for the Fleet application. For simplicity, token-based authentication is currently implemented, and the Vault server is running in development mode. The Vault UI can be accessed at:  \n[http://127.0.0.1:8201/ui/](http://127.0.0.1:8201/ui/)  \n\n  - **How Vault Fits Fleet's Current and Future Needs:**  \n    - **Transit Engine**: Vault can be used to encrypt and decrypt sensitive data (e.g., customer or driver information) without exposing encryption keys to the application. This ensures data security during transit.  \n    - **Database Secrets Engine**: Vault can dynamically generate database credentials for services, ensuring that secrets are short-lived and reducing the risk of credential leakage.  \n    - **Application Secrets**: Spring Boot applications can query Vault to fetch secrets stored under paths like `secrets/app-name`. This allows each microservice to securely retrieve its respective secrets (e.g., API keys, database credentials) at runtime.  \n\n  - Links referred:\n    - https://gist.github.com/Mishco/b47b341f852c5934cf736870f0b5da81\n    - https://hub.docker.com/r/hashicorp/vault\n\n8. **Kafka and ZooKeeper Setup**\n  - Setting up a reliable Kafka environment was crucial for Fleet's event-driven architecture. Learning how to properly configure Kafka and ZooKeeper in Docker Compose presented challenges, particularly with setting proper environment-variables, healthchecks etc. I'm using **Confluent Kafka and Zookeeper** as many enterpises are utilizing it.\n\n  - Links referred:\n    - https://www.geeksforgeeks.org/getting-started-with-spring-boot-3-kafka-over-docker-with-docker-composeyaml/   \n\n9. **Multi-Stage Docker Builds \u0026 Distroless Images**  \nLearned how to write efficient multi-stage Docker builds to minimize image size and improve security. Utilized distroless images for the runtime stage, resulting in lightweight containers with a reduced attack surface.\n  - Links referred:\n    - https://youtu.be/dwVPvZAPaxQ?si=FQKNxrB4xJxAH_Kc\n    - https://github.com/GoogleContainerTools/distroless/blob/main/java/README.md\n    - https://bell-sw.com/blog/distroless-containers-for-security-and-size/\n    - https://console.cloud.google.com/artifacts/docker/distroless/us/gcr.io/java21-debian12?inv=1\u0026invt=AbyJhg\n---\n\n## Installation 🛠️\n\n### Prerequisites\n- Java (v17)\n- Apache Maven (v3.9.9 or higher)\n- Docker (v27.3.1 or higher)\n- Docker compose (v2.30.3-desktop.1 since im using windows)\n- Python (v3.8.10)\n\n### Steps to Build the Application\nTo build the Fleet application, execute the following command:\n```bash\ncd tools/build  \n\n# Build the application with tests  \nsh compile.sh\n\n# Build the application but skip tests  \nsh compile-skip-tests.sh\n```\n\n### Steps to Run Pre-Commit Hooks\nFollow these steps to ensure pre-commit hooks are installed and executed correctly:\n\n1. **If Pre-Commit is Already Installed**:\n  Run the following commands:\n  ```bash\n  pre-commit install\n  pre-commit run --all\n  ```\n\n2. **If Pre-Commit is Not Installed**:\n  Ensure you are using Python 3.8.10 (newer Python and pre-commit versions may have compatibility issues). Then, execute:\n  ```bash\n  pip install -r requirements.txt\n  pre-commit install\n  pre-commit run --all\n  ```\n\n3. **If Using Windows and Pre-Commit Command is Not Found**:\n  Verify your Python version by running:\n  ```bash\n  python3 --version\n  ```\n  Ensure the output is:\n  ```\n  Python 3.8.10\n  ```\n\n  Then, use the following commands to install and run pre-commit hooks:\n  ```bash\n  python3 -m pre_commit install\n  python3 -m pre_commit run --all\n  ```\n\n4. **Auto update Pre-Commit Hooks**:\n```bash\npre-commit autoupdate\n```\nor\n```bash\npython3 -m pre_commit autoupdate\n```\n\n----\n\n\n### Steps to Run the Application\n\n----\n\n## Contributing 🤝\n- Direct pushes to the `main` branch are protected and not allowed. All changes must go through a pull request.\n- Once a pull request is merged, the corresponding branch will be deleted to keep the repository clean.\n\nContributions are welcome! Please follow these steps:\n1. Fork the repository.\n2. Create a new branch for your feature or bug fix.\n3. Commit your changes and push them to your fork.\n4. Submit a pull request with a detailed description of your changes.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faadimanchekar%2Ffleet","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Faadimanchekar%2Ffleet","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faadimanchekar%2Ffleet/lists"}