# Configuration All configuration lives in `src/main/resources/application.properties`. Values fall into two groups: - **Non-secret defaults** — model names, timeouts, retry policy, RSS URLs, log levels. These are literal values in the properties file and are safe to read in a review. - **Secrets and environment-specific endpoints** — resolved from environment variables via `${VAR}` placeholders. [`.env.example`](../.env.example) is the authoritative list of every variable, marked `REQUIRED` or `OPTIONAL`. ## Secret handling **No credential is ever committed.** Required secrets are declared *without* a fallback: ```properties openai.api.key=${OPENAI_API_KEY} ``` If the variable is absent, Spring throws `IllegalArgumentException: Could not resolve placeholder 'OPENAI_API_KEY'` and the application refuses to start. This is intentional. The alternative — an empty default — produces a service that boots happily and then fails every downstream call with an opaque `401`, usually in production, usually at 3am. A startup failure names the missing variable immediately. Optional values keep a default after the colon: ```properties minio.bucket-name=${MINIO_BUCKET_NAME:konturai} ``` ### Adding a new configuration value 1. If it is a credential, endpoint, or anything that differs per environment, use a `${VAR}` placeholder — no default for required secrets. 2. Add it to `.env.example` with a `REQUIRED`/`OPTIONAL` marker and a one-line comment. 3. Add it to `.env.production` on the server before merging. Never write a real value into `application.properties`, a test's `@TestPropertySource`, a shell script, or documentation. ## The Google service-account key `NanoBananaImageGenerationService` and `GeminiVideoGenerationService` authenticate to Vertex AI by loading `keys/google-key.json` from the classpath: ```java ClassPathResource resource = new ClassPathResource("keys/google-key.json"); ``` The file must exist at `src/main/resources/keys/google-key.json` at **build** time, so it is baked into the jar. It is gitignored and must be supplied out of band: ```bash cp /secure/path/google-key.json src/main/resources/keys/google-key.json ``` On the deployment host the file must be present in the checkout before the Docker image is built, since the `Dockerfile` uses `COPY . .`. If the file is missing the application still starts — image and video generation log an error and return `null`, while every other feature keeps working. ## Local development ```bash cp .env.example .env $EDITOR .env set -a && source .env && set +a ./mvnw spring-boot:run ``` For a fully local setup you need MongoDB on `localhost:27017`. Point `MINIO_ENDPOINT` at a local MinIO container, or leave the storage-backed endpoints unused. An alternative to `.env` is `src/main/resources/application-local.properties` (also gitignored), activated with `--spring.profiles.active=local`. ## Configuration reference by area | Area | Prefix | Notes | | --- | --- | --- | | MongoDB | `spring.data.mongodb.*` | 30s connect/socket/server-selection timeouts | | Object storage | `minio.*` | Stores generated reports and images | | Security | `security.jwt.*`, `encryption.*` | JWT secret must match the issuing auth service | | OpenAI | `openai.*` | `gpt-4o` for text, `gpt-4o-mini` for cheaper calls; retry with exponential backoff, max 3 concurrent requests | | Ollama | `ollama.*` | Self-hosted; very long timeouts (5h) for large generations | | Vertex AI | `google.*` | Imagen 3 for images, Veo 3 for video; 20s rate-limit spacing | | Serper | `serper.*` | Google search results for research reports | | Facebook | `facebook.*` | Posting, plus the hot-leads collector and call-centre sync | | RSS | `rss.*` | Five sources — see [rss-parsers.md](rss-parsers.md) | | Schedulers | `parser.scheduler.enabled`, `posting.scheduler.enabled` | Parser scheduler is **off** by default | | CORS | `cors.*` | Bound by `CorsProperties`, applied in `WebCorsConfig` | ## Rotating a credential 1. Issue the new credential with the provider. 2. Update `.env.production` on the deployment host. 3. Restart the container (`docker compose up -d` — see [deployment.md](deployment.md)). 4. Revoke the old credential. Because secrets are never baked into the image, rotation requires no rebuild.