108 lines
4.2 KiB
Markdown
108 lines
4.2 KiB
Markdown
# 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.
|