# chpr2011/incident-service architecture

> Architecture diagram of the GitHub repository chpr2011/incident-service, generated by GitDiagram from its file tree, README and a sample of source files (last updated 2026-06-28). It is an AI-made overview: check details against the source.

- Interactive diagram: https://gitdiagram.com/chpr2011/incident-service
- Repository: https://github.com/chpr2011/incident-service

## Overview

1. This repository is a single Spring Boot service, not a distributed system. The core runtime is Java 21 + Spring Boot 3.3.x, with Spring MVC, Spring Data JPA, Flyway, and H2 for local/test runs or PostgreSQL 16 in the Docker “prod” profile.

2. The architecture is intentionally layered around the `com.everbridge.incident` package:
   - `web` exposes REST endpoints and DTOs
   - `application` contains orchestration/business use cases
   - `domain` holds the pure incident model and status rules
   - `infrastructure` contains JPA repositories and event listeners
   - `common` provides cross-cutting request/error handling

3. The main HTTP entrypoint is `IncidentController`. It handles:
   - `POST /incidents` for intake with idempotency
   - `GET /incidents/{id}` for an incident plus history
   - `GET /incidents` for filtered/paginated search
   - `PATCH /incidents/{id}/status` for lifecycle transitions
   - `GET /incidents/{id}/history` for the audit trail

4. Request flow is conventional layered MVC: controller → `IncidentService` → domain rules → repositories. The controller only maps request/response shapes; it does not own business logic. Mapping between entity and API DTOs is isolated in `web/mapper/IncidentMapper` using MapStruct.

5. The domain layer is the main business boundary. `Incident`, `IncidentStatus`, `Severity`, `IncidentHistory`, and `StatusTransitionRules` model the lifecycle rules and immutable audit semantics. Invalid state changes are rejected in the domain/application flow, not in the controller.

6. Persistence is handled through Spring Data JPA repositories in `infrastructure/repository`. `IncidentRepository` supports id lookup and idempotent lookup by `externalReferenceId`; `IncidentSpecifications` provides composable filters for list queries. Hibernate optimistic locking via `@Version` is used to prevent lost updates and surface conflicts as 409s.

7. Audit recording is decoupled from the main write path using domain events. Status changes publish `IncidentStatusChangedEvent`, and `IncidentHistoryListener` persists append-only entries into `incident_history`. This keeps audit history authoritative and chronologically ordered without mixing it into controller code.

8. Cross-cutting request concerns live in `common`:
   - `CorrelationIdFilter` propagates or creates `X-Correlation-Id`
   - `GlobalExceptionHandler` converts errors into RFC 7807 `ProblemDetail` responses
   - custom exceptions represent not-found, invalid transition, and related business failures

9. Schema management is migration-based, not entity-auto-generated. Flyway scripts under `src/main/resources/db/migration` create `incidents` and `incident_history`, and the application explicitly disables `ddl-auto`. That makes the schema an explicit deployment boundary.

10. Observability is first-class and split across logs, metrics, and dashboards:
   - structured JSON logging via `logback-spring.xml`
   - Micrometer + Prometheus at `/actuator/prometheus`
   - Docker observability stack with Prometheus, Grafana, Loki, and Promtail
   - correlation IDs appear in logs and API error responses for traceability

11. Environment configuration is profile-driven. `application.yml`, `application-dev.yml`, and `application-docker.yml` switch between H2/local settings and Docker/PostgreSQL settings. The repo includes separate compose files for dev and prod, plus provisioning for Grafana datasources and dashboards.

12. The project is test-heavy and mirrors the production layers:
   - pure domain tests for transition rules
   - service unit tests with Mockito
   - repository tests with JPA/H2
   - WebMvc slice tests for controller + error handling
   - full integration tests with Spring Boot and real migrations
   This maps well to the architecture because each boundary is tested in isolation before the full stack.

13. The important diagram boundaries are: external HTTP clients, the web/API layer, the application service layer, the domain model, the persistence/event infrastructure, and the database. Around that core sit cross-cutting concerns for correlation IDs, error translation, logging, metrics, and environment-specific deployment via Docker Compose.

Main entry points: [`src/main/java/com/everbridge/incident/application/IncidentService.java`](https://github.com/chpr2011/incident-service/blob/main/src/main/java/com/everbridge/incident/application/IncidentService.java) (IncidentService), [`src/main/java/com/everbridge/incident/web/IncidentController.java`](https://github.com/chpr2011/incident-service/blob/main/src/main/java/com/everbridge/incident/web/IncidentController.java) (IncidentController), [`src/main/java/com/everbridge/incident/IncidentServiceApplication.java`](https://github.com/chpr2011/incident-service/blob/main/src/main/java/com/everbridge/incident/IncidentServiceApplication.java) (Incident App), [`src/main/java/com/everbridge/incident/domain/Incident.java`](https://github.com/chpr2011/incident-service/blob/main/src/main/java/com/everbridge/incident/domain/Incident.java) (Incident)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_external["Clients"]
end

subgraph group_web["Web API"]
  node_controller["IncidentController<br/>REST controller"]
  node_mapper["IncidentMapper<br/>DTO mapper"]
  node_create_req["Create DTO<br/>request/response DTOs"]
  node_status_req["Status DTO<br/>request/response DTOs"]
  node_incident_resp["Incident DTOs<br/>request/response DTOs"]
  node_errors["ProblemDetail<br/>exception handling"]
  node_filter["Correlation Filter<br/>http filter"]
end

subgraph group_core["Core Logic"]
  node_app["Incident App<br/>spring boot service"]
  node_service["IncidentService<br/>application service"]
  node_incident{{"Incident<br/>domain aggregate<br/>[Incident.java]"}}
  node_rules["Transition Rules<br/>domain rules"]
  node_status(("IncidentStatus<br/>domain enum"))
  node_severity(("Severity<br/>domain enum<br/>[Severity.java]"))
  node_history["IncidentHistory<br/>domain/audit model"]
  node_event{{"StatusChangedEvent<br/>domain event"}}
end

subgraph group_infra["Infrastructure"]
  node_repo[("IncidentRepository<br/>jpa repository")]
  node_specs["IncidentSpecifications<br/>query specs"]
  node_history_repo[("HistoryRepository<br/>jpa repository")]
  node_listener["HistoryListener<br/>event listener"]
end

subgraph group_ops["Ops"]
  node_flyway["Flyway Migrations<br/>schema migrations"]
  node_config["Profiles<br/>runtime config<br/>[application.yml]"]
  node_logging["Structured Logs<br/>observability config<br/>[logback-spring.xml]"]
  node_compose["Docker Stack<br/>deployment stack<br/>[docker-compose.yml]"]
  node_db[("PostgreSQL / H2<br/>database")]
end

node_controller -->|"maps"| node_mapper
node_controller -->|"calls"| node_service
node_controller -->|"errors"| node_errors
node_controller -->|"correlates"| node_filter
node_service -->|"uses"| node_incident
node_service -->|"validates"| node_rules
node_service -->|"persists"| node_repo
node_service -->|"queries"| node_specs
node_service -->|"publishes"| node_event
node_incident -->|"tracks"| node_status
node_incident -->|"classifies"| node_severity
node_incident -.->|"records"| node_history
node_event -->|"consumed by"| node_listener
node_listener -->|"writes"| node_history_repo
node_repo -->|"stores"| node_db
node_history_repo -->|"stores"| node_db
node_flyway -->|"migrates"| node_db
node_config -.->|"configures"| node_db
node_compose -.->|"supplies"| node_config
node_logging -.->|"correlates"| node_filter
node_app -->|"starts"| node_controller
node_app -->|"wires"| node_service
node_app -->|"wires"| node_repo
node_app -->|"wires"| node_listener

click node_app "https://github.com/chpr2011/incident-service/blob/main/src/main/java/com/everbridge/incident/IncidentServiceApplication.java"
click node_controller "https://github.com/chpr2011/incident-service/blob/main/src/main/java/com/everbridge/incident/web/IncidentController.java"
click node_mapper "https://github.com/chpr2011/incident-service/blob/main/src/main/java/com/everbridge/incident/web/mapper/IncidentMapper.java"
click node_create_req "https://github.com/chpr2011/incident-service/blob/main/src/main/java/com/everbridge/incident/web/dto/CreateIncidentRequest.java"
click node_status_req "https://github.com/chpr2011/incident-service/blob/main/src/main/java/com/everbridge/incident/web/dto/UpdateStatusRequest.java"
click node_incident_resp "https://github.com/chpr2011/incident-service/blob/main/src/main/java/com/everbridge/incident/web/dto/IncidentResponse.java"
click node_service "https://github.com/chpr2011/incident-service/blob/main/src/main/java/com/everbridge/incident/application/IncidentService.java"
click node_incident "https://github.com/chpr2011/incident-service/blob/main/src/main/java/com/everbridge/incident/domain/Incident.java"
click node_rules "https://github.com/chpr2011/incident-service/blob/main/src/main/java/com/everbridge/incident/domain/StatusTransitionRules.java"
click node_status "https://github.com/chpr2011/incident-service/blob/main/src/main/java/com/everbridge/incident/domain/IncidentStatus.java"
click node_severity "https://github.com/chpr2011/incident-service/blob/main/src/main/java/com/everbridge/incident/domain/Severity.java"
click node_history "https://github.com/chpr2011/incident-service/blob/main/src/main/java/com/everbridge/incident/domain/IncidentHistory.java"
click node_event "https://github.com/chpr2011/incident-service/blob/main/src/main/java/com/everbridge/incident/domain/events/IncidentStatusChangedEvent.java"
click node_repo "https://github.com/chpr2011/incident-service/blob/main/src/main/java/com/everbridge/incident/infrastructure/repository/IncidentRepository.java"
click node_specs "https://github.com/chpr2011/incident-service/blob/main/src/main/java/com/everbridge/incident/infrastructure/repository/IncidentSpecifications.java"
click node_history_repo "https://github.com/chpr2011/incident-service/blob/main/src/main/java/com/everbridge/incident/infrastructure/repository/IncidentHistoryRepository.java"
click node_listener "https://github.com/chpr2011/incident-service/blob/main/src/main/java/com/everbridge/incident/infrastructure/events/IncidentHistoryListener.java"
click node_errors "https://github.com/chpr2011/incident-service/blob/main/src/main/java/com/everbridge/incident/common/exception/GlobalExceptionHandler.java"
click node_filter "https://github.com/chpr2011/incident-service/blob/main/src/main/java/com/everbridge/incident/common/filter/CorrelationIdFilter.java"
click node_flyway "https://github.com/chpr2011/incident-service/blob/main/src/main/resources/db/migration/V1__create_incidents.sql"
click node_config "https://github.com/chpr2011/incident-service/blob/main/src/main/resources/application.yml"
click node_logging "https://github.com/chpr2011/incident-service/blob/main/src/main/resources/logback-spring.xml"
click node_compose "https://github.com/chpr2011/incident-service/blob/main/docker-compose.yml"

classDef toneNeutral fill:#f8fafc,stroke:#334155,stroke-width:1.5px,color:#0f172a
classDef toneBlue fill:#dbeafe,stroke:#2563eb,stroke-width:1.5px,color:#172554
classDef toneAmber fill:#fef3c7,stroke:#d97706,stroke-width:1.5px,color:#78350f
classDef toneMint fill:#dcfce7,stroke:#16a34a,stroke-width:1.5px,color:#14532d
classDef toneRose fill:#ffe4e6,stroke:#e11d48,stroke-width:1.5px,color:#881337
classDef toneIndigo fill:#e0e7ff,stroke:#4f46e5,stroke-width:1.5px,color:#312e81
classDef toneTeal fill:#ccfbf1,stroke:#0f766e,stroke-width:1.5px,color:#134e4a
class node_controller,node_mapper,node_create_req,node_status_req,node_incident_resp,node_errors,node_filter toneAmber
class node_app,node_service,node_incident,node_rules,node_status,node_severity,node_history,node_event toneMint
class node_repo,node_specs,node_history_repo,node_listener toneRose
class node_flyway,node_config,node_logging,node_compose,node_db toneIndigo
```

## Components

### Web API

REST entrypoints, DTOs, and request mapping

- [IncidentController](https://github.com/chpr2011/incident-service/blob/main/src/main/java/com/everbridge/incident/web/IncidentController.java): REST controller · HTTP endpoints for create, read, search, and status updates · `src/main/java/com/everbridge/incident/web/IncidentController.java`
- [IncidentMapper](https://github.com/chpr2011/incident-service/blob/main/src/main/java/com/everbridge/incident/web/mapper/IncidentMapper.java): DTO mapper · MapStruct mapping between API DTOs and incident models · `src/main/java/com/everbridge/incident/web/mapper/IncidentMapper.java`
- [Create DTO](https://github.com/chpr2011/incident-service/blob/main/src/main/java/com/everbridge/incident/web/dto/CreateIncidentRequest.java): request/response DTOs · Incident create and detail API shapes · `src/main/java/com/everbridge/incident/web/dto/CreateIncidentRequest.java`
- [Status DTO](https://github.com/chpr2011/incident-service/blob/main/src/main/java/com/everbridge/incident/web/dto/UpdateStatusRequest.java): request/response DTOs · Status update and history API shapes · `src/main/java/com/everbridge/incident/web/dto/UpdateStatusRequest.java`
- [Incident DTOs](https://github.com/chpr2011/incident-service/blob/main/src/main/java/com/everbridge/incident/web/dto/IncidentResponse.java): request/response DTOs · List and detail responses for incidents and history · `src/main/java/com/everbridge/incident/web/dto/IncidentResponse.java`
- [ProblemDetail](https://github.com/chpr2011/incident-service/blob/main/src/main/java/com/everbridge/incident/common/exception/GlobalExceptionHandler.java): exception handling · Translates business and request failures into RFC 7807 responses · `src/main/java/com/everbridge/incident/common/exception/GlobalExceptionHandler.java`
- [Correlation Filter](https://github.com/chpr2011/incident-service/blob/main/src/main/java/com/everbridge/incident/common/filter/CorrelationIdFilter.java): http filter · Propagates or creates correlation IDs for requests and logs · `src/main/java/com/everbridge/incident/common/filter/CorrelationIdFilter.java`

### Core Logic

Application orchestration and domain rules

- [Incident App](https://github.com/chpr2011/incident-service/blob/main/src/main/java/com/everbridge/incident/IncidentServiceApplication.java): spring boot service · Java 21 Spring Boot entrypoint for the incident service · `src/main/java/com/everbridge/incident/IncidentServiceApplication.java`
- [IncidentService](https://github.com/chpr2011/incident-service/blob/main/src/main/java/com/everbridge/incident/application/IncidentService.java): application service · Use case orchestration for intake, search, and lifecycle transitions · `src/main/java/com/everbridge/incident/application/IncidentService.java`
- [Incident](https://github.com/chpr2011/incident-service/blob/main/src/main/java/com/everbridge/incident/domain/Incident.java): domain aggregate · Core incident model and state transitions · `src/main/java/com/everbridge/incident/domain/Incident.java`
- [Transition Rules](https://github.com/chpr2011/incident-service/blob/main/src/main/java/com/everbridge/incident/domain/StatusTransitionRules.java): domain rules · Validates allowed status changes · `src/main/java/com/everbridge/incident/domain/StatusTransitionRules.java`
- [IncidentStatus](https://github.com/chpr2011/incident-service/blob/main/src/main/java/com/everbridge/incident/domain/IncidentStatus.java): domain enum · Incident lifecycle states · `src/main/java/com/everbridge/incident/domain/IncidentStatus.java`
- [Severity](https://github.com/chpr2011/incident-service/blob/main/src/main/java/com/everbridge/incident/domain/Severity.java): domain enum · Incident severity classification · `src/main/java/com/everbridge/incident/domain/Severity.java`
- [IncidentHistory](https://github.com/chpr2011/incident-service/blob/main/src/main/java/com/everbridge/incident/domain/IncidentHistory.java): domain/audit model · Append-only audit entry for incident changes · `src/main/java/com/everbridge/incident/domain/IncidentHistory.java`
- [StatusChangedEvent](https://github.com/chpr2011/incident-service/blob/main/src/main/java/com/everbridge/incident/domain/events/IncidentStatusChangedEvent.java): domain event · Published when incident status changes · `src/main/java/com/everbridge/incident/domain/events/IncidentStatusChangedEvent.java`

### Infrastructure

Persistence and event-driven side effects

- [IncidentRepository](https://github.com/chpr2011/incident-service/blob/main/src/main/java/com/everbridge/incident/infrastructure/repository/IncidentRepository.java): jpa repository · Incident persistence with id lookup and idempotent external reference lookup · `src/main/java/com/everbridge/incident/infrastructure/repository/IncidentRepository.java`
- [IncidentSpecifications](https://github.com/chpr2011/incident-service/blob/main/src/main/java/com/everbridge/incident/infrastructure/repository/IncidentSpecifications.java): query specs · Composable filters for list and search queries · `src/main/java/com/everbridge/incident/infrastructure/repository/IncidentSpecifications.java`
- [HistoryRepository](https://github.com/chpr2011/incident-service/blob/main/src/main/java/com/everbridge/incident/infrastructure/repository/IncidentHistoryRepository.java): jpa repository · Stores append-only incident history entries · `src/main/java/com/everbridge/incident/infrastructure/repository/IncidentHistoryRepository.java`
- [HistoryListener](https://github.com/chpr2011/incident-service/blob/main/src/main/java/com/everbridge/incident/infrastructure/events/IncidentHistoryListener.java): event listener · Persists audit history from status change events · `src/main/java/com/everbridge/incident/infrastructure/events/IncidentHistoryListener.java`

### Ops

Configuration, schema, and observability

- [Flyway Migrations](https://github.com/chpr2011/incident-service/blob/main/src/main/resources/db/migration/V1__create_incidents.sql): schema migrations · Explicit database schema creation and evolution · `src/main/resources/db/migration/V1__create_incidents.sql`
- [Profiles](https://github.com/chpr2011/incident-service/blob/main/src/main/resources/application.yml): runtime config · Environment-specific settings for local, dev, and Docker deployments · `src/main/resources/application.yml`
- [Structured Logs](https://github.com/chpr2011/incident-service/blob/main/src/main/resources/logback-spring.xml): observability config · JSON logging and correlation-aware log output · `src/main/resources/logback-spring.xml`
- [Docker Stack](https://github.com/chpr2011/incident-service/blob/main/docker-compose.yml): deployment stack · Compose-based app and observability environment · `docker-compose.yml`
- **PostgreSQL / H2**: database · Primary relational store for incidents and history

## Connections

- IncidentController → IncidentMapper: maps · Transforms API payloads to and from domain-facing shapes
- IncidentController → IncidentService: calls · Delegates request handling to the application layer
- IncidentController → ProblemDetail: errors · Business and validation failures become ProblemDetail responses
- IncidentController → Correlation Filter: correlates · Requests receive or propagate correlation IDs
- IncidentService → Incident: uses · Coordinates incident lifecycle and state changes
- IncidentService → Transition Rules: validates · Checks permitted status transitions
- IncidentService → IncidentRepository: persists · Loads and saves incidents
- IncidentService → IncidentSpecifications: queries · Builds filtered incident searches
- IncidentService → StatusChangedEvent: publishes · Emits status change events after successful transitions
- Incident → IncidentStatus: tracks · Incident lifecycle state
- Incident → Severity: classifies · Severity is part of the incident model
- Incident → IncidentHistory: records · Incident changes are represented as audit entries
- StatusChangedEvent → HistoryListener: consumed by · Status change events trigger audit persistence
- HistoryListener → HistoryRepository: writes · Appends history entries
- IncidentRepository → PostgreSQL / H2: stores · Incident entities live in the relational database
- HistoryRepository → PostgreSQL / H2: stores · Audit entries live in the relational database
- Flyway Migrations → PostgreSQL / H2: migrates · Schema is created and evolved via migrations
- Profiles → PostgreSQL / H2: configures · Profiles switch between H2 and PostgreSQL settings
- Docker Stack → Profiles: supplies · Docker profiles and compose files drive runtime settings
- Structured Logs → Correlation Filter: correlates · Correlation IDs are emitted into structured logs
- Incident App → IncidentController: starts · Bootstraps the REST API and application context
- Incident App → IncidentService: wires · Creates the use case layer and its dependencies
- Incident App → IncidentRepository: wires · Enables JPA persistence
- Incident App → HistoryListener: wires · Registers domain event listeners
