Spring Boot service that maintains integration definitions for FINT Flyt tenants. It exposes an internal API for creating, updating, and querying integrations, persists state in PostgreSQL, validates references to configuration documents, and serves Kafka request/reply contracts that other Flyt services depend on.
- RESTful integration registry — Spring MVC controller for listing, fetching, creating, and patching integrations under
/api/intern/integrasjoner. - PostgreSQL persistence — JPA-backed repository with Flyway migrations ensuring a unique key per source application integration.
- Kafka request/reply bridges — Consumers and producers that expose integration lookups and configuration fetches over namespaced request topics.
- Context-aware validation — Custom Jakarta Bean Validation constraints that query configuration state before accepting active configuration changes.
- Authorization-aware listings — Optional
UserAuthorizationServiceguard that filters data by the caller’s allowed source applications.
| Component | Responsibility |
|---|---|
IntegrationController |
Handles internal HTTP requests, enforces authorization rules, and orchestrates validation. |
IntegrationService |
Coordinates repository access, DTO mapping, and business rules for CRUD operations. |
IntegrationRepository |
Spring Data JPA repository storing integrations in PostgreSQL with uniqueness constraints. |
IntegrationMappingService |
Maps between JPA entities and API DTOs to keep persistence separate from transport concerns. |
IntegrationValidatorFactory & constraints |
Builds validators with contextual payload so active configuration IDs are verified before persist. |
ConfigurationRequestProducerService |
Issues Kafka request/reply calls to fetch configuration snapshots used during validation. |
IntegrationRequestConsumerConfiguration |
Exposes Kafka listeners that answer integration lookup requests by ID or by (sourceApp, integrationId) tuple. |
ActiveConfigurationIdRequestConsumerConfiguration |
Serves active configuration IDs over Kafka topics so dependent services can resolve them dynamically. |
Base path: /api/intern/integrasjoner
| Method | Path | Description | Request body | Response |
|---|---|---|---|---|
GET |
/ |
List integrations. Optional sourceApplicationId filters the result. |
– | 200 OK with IntegrationDto[]. |
GET |
/?side&antall&sorteringFelt&sorteringRetning |
Paged listing with Spring Data pagination parameters and optional sourceApplicationId filter. |
– | 200 OK with a Page<IntegrationDto> payload. |
GET |
/{integrationId} |
Fetch a single integration by ID. Authorization rules verified when permission consumer is enabled. | – | 200 OK with an IntegrationDto, 404 when not found. |
POST |
/ |
Create a new integration. Rejects duplicates per source application integration ID. | IntegrationPostDto JSON (see below). |
200 OK with the created IntegrationDto. 409 on clash. |
PATCH |
/{integrationId} |
Apply partial updates to destination, state, or active configuration. | IntegrationPatchDto JSON. |
200 OK with the updated IntegrationDto, 422 on invalid changes. |
Example IntegrationPostDto payload:
{
"sourceApplicationId": 15,
"sourceApplicationIntegrationId": "case-updates",
"destination": "https://org.example.no/integrations/case-updates"
}Validation failures yield 422 Unprocessable Entity with aggregated error messages. When user-permission checks are active, access to non-authorized source applications returns 403 Forbidden.
ConfigurationRequestProducerServiceperforms request/reply lookups on theconfigurationtopic to validate referenced configuration IDs.IntegrationRequestConsumerConfigurationregisters consumers that answer:- Integration by
integration-id. - Integration by
(source-application-id, source-application-integration-id).
- Integration by
ActiveConfigurationIdRequestConsumerConfigurationexposes a request endpoint that resolves an integration’s current active configuration ID.
All topics use the Flyt domain context defaults with per-tenant prefixes, five-minute retention, and a 15-second reply timeout for outbound requests.
The service does not define scheduled jobs; configuration validation happens inline during PATCH operations.
Spring profiles layer common Flyt settings: flyt-kafka, flyt-logging, flyt-postgres, and flyt-web-resource-server.
Key properties:
| Property | Description |
|---|---|
fint.application-id |
Default application ID used for Kafka client IDs and topic prefixes. |
novari.kafka.topic.orgId |
Overridden per kustomize overlay to scope Kafka ACLs and topic prefixes. |
fint.database.url, fint.database.username, fint.database.password |
PostgreSQL connection parameters supplied through secrets. |
spring.security.oauth2.resourceserver.jwt.issuer-uri |
Identity provider for JWT validation. |
management.endpoints.web.exposure.include |
Actuator endpoints exposed (health, info, prometheus). |
Secrets referenced by the base manifest must provide database credentials and OAuth client configuration.
Prerequisites:
- Java 25+
- Dockerized or local PostgreSQL instance
- Kafka broker (local or containerized)
Useful commands:
./gradlew clean build # compile sources and run tests
./gradlew test # unit test suite
./gradlew bootRun # start the application with Flyt profiles
docker compose up -d # start PostgreSQL and Kafka locally
docker compose --profile app up --build # start app, PostgreSQL, and Kafka in containersUse SPRING_PROFILES_ACTIVE=local-staging to apply the local overrides in application-local-staging.yaml. Provide a PostgreSQL instance (defaults to jdbc:postgresql://localhost:5438/fint-flyt-integration-service) and a Kafka broker on localhost:9092.
For local development from IntelliJ or bootRun, docker compose up -d starts:
- PostgreSQL on
localhost:5438 - Apache Kafka
3.8.1onlocalhost:9092
If you also want the application in Docker, use docker compose --profile app up --build. Then the app is exposed on http://localhost:8090.
The compose setup creates the fintlabs_no schema automatically so the local-staging profile works unchanged. Wait until PostgreSQL is healthy before starting the app locally.
Kustomize structure:
kustomize/base/holds the shared Application manifest, database/env wiring, and Actuator configuration.kustomize/overlays/<org>/<env>/includes tenant-specific patches (namespace, labels, Kafka topics, and servlet context paths).
Templates live under kustomize/templates/:
overlay.yaml.tpl— single source of truth for overlay content.
Regenerate overlays after editing templates:
./script/render-overlay.shThe script iterates over existing overlays, substitutes organization-specific values, and rewrites kustomization.yaml files in place.
- OAuth2 resource server with JWT validation against
https://idp.felleskomponent.no. - Internal API is gated by
novari.flyt.web-resource-server.security.api.internalsettings; optional user-permissions consumer restricts visibility to authorized source applications.
- Readiness probe at
/actuator/health. - Prometheus metrics exposed at
/actuator/prometheus. - Structured logging leverages standard Spring Boot logging context.
- Validation rules rely on Kafka lookups; stub
ConfigurationRequestProducerServicein tests when asserting constraint behavior. - Flyway migrations live under
src/main/resources/db/migration; add new scripts for schema changes instead of modifying existing ones. IntegrationServicehandles entity mapping—prefer updating the mapper rather than touching controller DTO conversion.
- Create a topic branch for your change.
- Run
./gradlew testbefore opening a pull request. - If you modify kustomize content, run
./script/render-overlay.shand commit the generated overlays. - Add or update unit tests to cover new functionality.
———
FINT Flyt Integration Service is maintained by the FINT Flyt team. Reach out on the internal Slack channel or file an issue in this repository for questions or enhancement ideas.