{"id":27455594,"url":"https://github.com/luismr/flight-tracker-event-server-java","last_synced_at":"2025-08-16T09:09:51.383Z","repository":{"id":286190762,"uuid":"960661123","full_name":"luismr/flight-tracker-event-server-java","owner":"luismr","description":"A Spring Boot application for tracking flight events.","archived":false,"fork":false,"pushed_at":"2025-05-06T01:26:35.000Z","size":746,"stargazers_count":25,"open_issues_count":0,"forks_count":4,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-05-06T02:22:45.405Z","etag":null,"topics":["java","java-21","java21","kafka","openapi-specification","openapi3","postgres","postgresql","redis","spring-boot","swagger","swagger-ui"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/luismr.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","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-04-04T20:32:27.000Z","updated_at":"2025-05-01T20:53:12.000Z","dependencies_parsed_at":"2025-04-04T21:37:04.664Z","dependency_job_id":"b0a84c45-ca5c-43d3-ab4f-b1e69106f80b","html_url":"https://github.com/luismr/flight-tracker-event-server-java","commit_stats":null,"previous_names":["luismr/flight-tracker-event-server-java"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/luismr/flight-tracker-event-server-java","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/luismr%2Fflight-tracker-event-server-java","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/luismr%2Fflight-tracker-event-server-java/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/luismr%2Fflight-tracker-event-server-java/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/luismr%2Fflight-tracker-event-server-java/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/luismr","download_url":"https://codeload.github.com/luismr/flight-tracker-event-server-java/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/luismr%2Fflight-tracker-event-server-java/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":270690521,"owners_count":24628903,"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","status":"online","status_checked_at":"2025-08-16T02:00:11.002Z","response_time":91,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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","java-21","java21","kafka","openapi-specification","openapi3","postgres","postgresql","redis","spring-boot","swagger","swagger-ui"],"created_at":"2025-04-15T16:44:14.878Z","updated_at":"2025-08-16T09:09:51.365Z","avatar_url":"https://github.com/luismr.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Flight Tracker Event Server\n\n![Java](https://img.shields.io/badge/Java-21-blue)\n![SpringBoot](https://img.shields.io/badge/SpringBoot-3.4.x-blue)\n![Swagger](https://img.shields.io/badge/Swagger-3.0-orange)\n![OpenAPI](https://img.shields.io/badge/OpenAPI-3.0-orange)\n![Kafka](https://img.shields.io/badge/Kafka-4.x-red)\n![Redis](https://img.shields.io/badge/Redis-7.4-green)\n![PostgreSQL](https://img.shields.io/badge/PostgreSQL-17-green)\n![JUnit](https://img.shields.io/badge/JUnit-5.x-blue)\n![JaCoCo](https://img.shields.io/badge/JaCoCo-0.8.x-blue)\n\n## Table of Contents\n\n- [Build Status](#build-status)\n- [Features](#features)\n- [Prerequisites](#prerequisites)\n- [Configuration](#configuration)\n  - [Kafka Configuration](#kafka-configuration)\n    - [Component Control](#component-control)\n  - [Database](#database)\n    - [Benefits of Write/Read Replicas](#benefits-of-writeread-replicas)\n    - [When to Use Write/Read Replicas](#when-to-use-writeread-replicas)\n    - [Configuration](#configuration-1)\n    - [How Datasource Routing Works](#how-datasource-routing-works)\n  - [Redis](#redis)\n  - [Clock Configuration](#clock-configuration)\n  - [API Documentation](#api-documentation)\n- [Development](#development)\n  - [Running the Application](#running-the-application)\n  - [Testing](#testing)\n- [API Documentation](#api-documentation-1)\n- [Getting Started](#getting-started)\n  - [External Dependencies](#external-dependencies)\n  - [Using Docker Compose](#using-docker-compose)\n  - [Service Details](#service-details)\n  - [Manual Service Management](#manual-service-management)\n  - [Cloning the Repository](#cloning-the-repository)\n  - [Building](#building)\n- [Contributing](#contributing)\n- [GitHub Actions Permissions](#github-actions-permissions)\n- [Read Write Datasource Routing](#read-write-datasource-routing)\n- [Project Structure](#project-structure)\n- [Analysis and Decisions](#analysis-and-decisions)\n  - [Architecture Decision Records (ADRs)](#architecture-decision-records-adrs)\n  - [Technical Analysis](#technical-analysis)\n- [License](#license)\n\nA Spring Boot application for tracking flight events.\n\n## Build Status\n\n[![Java CI with Maven](https://github.com/luismr/flight-tracker-event-server-java/actions/workflows/maven.yml/badge.svg)](https://github.com/luismr/flight-tracker-event-server-java/actions/workflows/maven.yml)\n![Coverage](badges/jacoco.svg)\n![Branches](badges/branches.svg)\n\n## Features\n\n- Real-time flight position tracking\n- Kafka-based event streaming\n- PostgreSQL database with read-write routing\n- Redis caching\n- Swagger/OpenAPI documentation\n- Configurable timezone support\n\n## Prerequisites\n\n- Java 17 or later\n- Docker and Docker Compose\n- PostgreSQL\n- Redis\n- Kafka\n\n## Configuration\n\nThe application can be configured through `application.yml`. Key configurations include:\n\n### Kafka Configuration\n\nThe application uses Kafka for event streaming and real-time data processing. Here's the complete Kafka configuration:\n\n```yaml\nspring:\n  kafka:\n    bootstrap-servers: localhost:9092\n    consumer:\n      group-id: flight-tracker-group\n      auto-offset-reset: earliest\n      key-deserializer: org.apache.kafka.common.serialization.StringDeserializer\n      value-deserializer: org.springframework.kafka.support.serializer.JsonDeserializer\n      properties:\n        spring.json.trusted.packages: \"dev.luismachadoreis.flighttracker.server.ping.application.dto\"\n    topic:\n      flight-positions: flight-positions\n      ping-created: ping-created\n```\n\n#### Component Control\n\nYou can enable or disable various Kafka components and WebSocket notifications:\n\n```yaml\napp:\n  flight-data:\n    subscriber:\n      enabled: true  # Enable/disable flight data Kafka subscriber\n  ping:\n    subscriber:\n      enabled: true  # Enable/disable ping Kafka subscriber\n    publisher:\n      enabled: true  # Enable/disable ping Kafka publisher\n    websocket:\n      enabled: true  # Enable/disable WebSocket notifications\n```\n![Load Balancing](docs/diagrams/arch_diagram_load_balancing.png)  \n\nThese settings allow you to:\n- Control Kafka message consumption for flight data\n- Control Kafka message consumption for ping events\n- Control Kafka message publishing for ping events\n- Enable/disable WebSocket real-time notifications\n\n### Database\n\nThe application supports a Write/Read replica pattern for database operations. This pattern separates read and write operations to different database instances, providing several benefits:\n\n![Database Write/Read Replicas](docs/diagrams/arch_diagram_datasource_read_write.png)  \n\n#### Benefits of Write/Read Replicas\n\n1. **Improved Read Performance**\n   - Read operations are distributed across multiple replicas\n   - Reduced load on the primary database\n   - Better scalability for read-heavy workloads\n\n2. **High Availability**\n   - If the primary database fails, read replicas can continue serving read requests\n   - Automatic failover capabilities\n   - Reduced downtime impact\n\n3. **Geographic Distribution**\n   - Read replicas can be placed closer to users\n   - Reduced latency for read operations\n   - Better global performance\n\n#### When to Use Write/Read Replicas\n\nConsider implementing Write/Read replicas when:\n- Your application has a high read-to-write ratio (e.g., 80% reads, 20% writes)\n- You need to scale read operations independently\n- You require high availability and disaster recovery\n- You have geographically distributed users\n- Your application has reporting or analytics features that require heavy read operations\n\n#### Configuration\n\n```yaml\nspring:\n  datasource:\n    writer:\n      jdbcUrl: jdbc:postgresql://localhost:5432/flighttracker\n      username: flighttracker\n      password: flighttracker\n    reader:\n      jdbcUrl: jdbc:postgresql://localhost:5433/flighttracker\n      username: flighttracker\n      password: flighttracker\n```\n\n#### How Datasource Routing Works\n\nThe application uses Spring's `@Transactional` annotation to determine which datasource to use. Here's how it works:\n\n![Datasource Routing](docs/diagrams/arch_diagram_datasource_routing.png)  \n\n1. **Read Operations**\n   ```java\n   @Transactional(readOnly = true)\n   public List\u003cFlight\u003e getRecentFlights() {\n       // This will use the reader datasource\n       return flightRepository.findAll();\n   }\n   ```\n\n2. **Write Operations**\n   ```java\n   @Transactional\n   public void saveFlight(Flight flight) {\n       // This will use the writer datasource\n       flightRepository.save(flight);\n   }\n   ```\n\n3. **Mixed Operations**\n   ```java\n   @Transactional\n   public void updateFlightStatus(String flightId, Status newStatus) {\n       // This will use the writer datasource for the entire method\n       Flight flight = flightRepository.findById(flightId);\n       flight.setStatus(newStatus);\n       flightRepository.save(flight);\n   }\n   ```\n\nThe routing is handled by:\n- `ReadWriteRoutingAspect`: Intercepts `@Transactional` annotations\n- `DbContextHolder`: Maintains the current context in a ThreadLocal\n- `RoutingDataSource`: Routes the request to the appropriate datasource\n\n**Important Notes:**\n- Methods without `@Transactional` will use the writer datasource by default\n- Nested transactions inherit the datasource from the outer transaction\n- The `readOnly` flag is the key to determining which datasource to use\n\n### Redis\n\n```yaml\nspring:\n  redis:\n    host: localhost\n    port: 6379\n```\n\n### Clock Configuration\n\nThe application uses a configurable clock for timestamp operations. By default, it uses UTC:\n\n```yaml\napp:\n  clock:\n    timezone: UTC\n```\n\nYou can change the timezone to any valid timezone ID (e.g., \"America/New_York\", \"Europe/London\"):\n\n```yaml\napp:\n  clock:\n    timezone: America/New_York\n```\n\n### API Documentation\n\nSwagger UI is available at `/swagger-ui.html` with the following configuration:\n\n```yaml\nspringdoc:\n  api-docs:\n    path: /api-docs\n  swagger-ui:\n    path: /swagger-ui.html\n```\n\n## Development\n\n### Running the Application\n\n1. Start the required services using Docker Compose:\n   ```bash\n   docker-compose up -d\n   ```\n\n2. Run the application:\n   ```bash\n   ./mvnw spring-boot:run\n   ```\n\n### Testing\n\nRun the tests:\n```bash\n./mvnw test\n```\n\n## API Documentation\n\nThe API documentation is available at:\n- Swagger UI: http://localhost:8080/swagger-ui.html\n- OpenAPI JSON: http://localhost:8080/api-docs\n\n## Getting Started\n\n### External Dependencies\n\nThe application requires the following external services:\n\n- Redis 7.4\n- PostgreSQL 17\n- Apache Kafka 4\n\n#### Using Docker Compose\n\nThe project includes a `docker-compose.yml`","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fluismr%2Fflight-tracker-event-server-java","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fluismr%2Fflight-tracker-event-server-java","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fluismr%2Fflight-tracker-event-server-java/lists"}