134 lines
4.4 KiB
Markdown
134 lines
4.4 KiB
Markdown
# Development
|
|
|
|
## Prerequisites
|
|
|
|
- **JDK 21** (Temurin recommended)
|
|
- **MongoDB** reachable at `MONGODB_HOST:MONGODB_PORT`
|
|
- Maven is not required — use the bundled wrapper (`./mvnw`)
|
|
|
|
## Setup
|
|
|
|
```bash
|
|
cp .env.example .env
|
|
$EDITOR .env # fill in REQUIRED values
|
|
set -a && source .env && set +a
|
|
./mvnw spring-boot:run
|
|
```
|
|
|
|
`http://localhost:8080/swagger-ui.html` gives you an interactive client; use the
|
|
**Authorize** button to supply a JWT.
|
|
|
|
## Common commands
|
|
|
|
```bash
|
|
./mvnw clean verify # unit tests + coverage gate — run before pushing
|
|
./mvnw test # unit tests only
|
|
./mvnw clean package # build the jar
|
|
./mvnw spring-boot:run # run locally
|
|
./mvnw test -Dtest=JwtServiceTest # a single test class
|
|
```
|
|
|
|
Helper scripts in [`scripts/`](../scripts):
|
|
|
|
| Script | Purpose |
|
|
| --- | --- |
|
|
| `run-parser.sh` | Preflight checks then start the application |
|
|
| `smoke-mongodb.sh` | Verify MongoDB reachability and print a connection string |
|
|
| `smoke-openai-api.sh` | Verify `OPENAI_API_KEY` works against the OpenAI API |
|
|
| `smoke-research-api.sh` | Exercise the report endpoints against a running instance |
|
|
|
|
## Testing
|
|
|
|
Two tiers, separated by an environment variable:
|
|
|
|
**Unit tests** run by default. They mock collaborators and never touch the network.
|
|
This is what CI and `./mvnw verify` execute.
|
|
|
|
**Integration tests** boot the full Spring context and need real MongoDB plus valid
|
|
credentials. They are annotated:
|
|
|
|
```java
|
|
@SpringBootTest
|
|
@EnabledIfEnvironmentVariable(named = "RUN_INTEGRATION_TESTS", matches = "true")
|
|
```
|
|
|
|
so they are skipped unless you opt in:
|
|
|
|
```bash
|
|
RUN_INTEGRATION_TESTS=true ./mvnw verify
|
|
```
|
|
|
|
Surefire additionally excludes the `integration` JUnit tag (see `pom.xml`).
|
|
|
|
### Coverage gate
|
|
|
|
`verify` fails if line coverage drops below **80%** on any of:
|
|
|
|
- `PostingTaskService`
|
|
- `JwtService`
|
|
- `SocialMediaCredentialsService`
|
|
|
|
Report: `target/site/jacoco/index.html`. To extend the gate to another class, add it to
|
|
the JaCoCo `qg01-coverage-check` rule in `pom.xml`.
|
|
|
|
### Test credentials
|
|
|
|
Tests must never contain real credentials. Use placeholders that resolve from the
|
|
environment:
|
|
|
|
```java
|
|
@TestPropertySource(properties = {
|
|
"spring.data.mongodb.host=${MONGODB_HOST:localhost}",
|
|
"spring.data.mongodb.username=${MONGODB_USERNAME:}"
|
|
})
|
|
```
|
|
|
|
## Conventions
|
|
|
|
- **Java 21**, Lombok for boilerplate (excluded from the packaged jar).
|
|
- Constructor injection, not field injection — see `ParserManagerService`.
|
|
- Controllers stay thin: validate, delegate to a service, return a DTO. No business
|
|
logic and no repository access from a controller.
|
|
- Never return a `model` document directly from a controller — map it to a `dto`.
|
|
- Throw domain exceptions from `exception/` and let `GlobalExceptionHandler` render
|
|
them; do not build error responses by hand.
|
|
- Long-running AI calls belong on an async executor (`AsyncConfig`), not the request
|
|
thread.
|
|
- Existing code mixes Russian and English comments. New comments should be in English.
|
|
|
|
## Adding an RSS source
|
|
|
|
`ParserManagerService` discovers parsers through Spring, so no registry needs editing:
|
|
|
|
1. Add `rss.<source>.url` to `application.properties`.
|
|
2. Implement `ParserService` — return a unique `getSourceName()` and implement
|
|
`parseAndSaveRssFeed()`. Model it on `KursivParserService`.
|
|
3. Annotate the scheduled entry point with `@Scheduled`, matching the cadence of
|
|
comparable sources (5 min for high-volume, 30 min otherwise).
|
|
4. Add a unit test alongside `KursivParserServiceTest`.
|
|
5. Add a log level line in `application.properties`.
|
|
6. Document the source in [rss-parsers.md](rss-parsers.md).
|
|
|
|
## Adding an endpoint
|
|
|
|
1. Define request/response DTOs in `dto/` with Bean Validation annotations.
|
|
2. Add the handler to the relevant controller; extract the caller with
|
|
`jwtService.extractUserIdFromHeader(authHeader)`.
|
|
3. Put the logic in a service; add a repository method if persistence is needed.
|
|
4. Add unit tests for the service.
|
|
5. Document it under [`docs/api/`](api/README.md) and update that index.
|
|
|
|
## Adding configuration
|
|
|
|
See [configuration.md](configuration.md#adding-a-new-configuration-value). In short:
|
|
environment placeholder, no default for secrets, and update `.env.example`.
|
|
|
|
## Before you push
|
|
|
|
```bash
|
|
./mvnw clean verify
|
|
git status # nothing unexpected staged
|
|
```
|
|
|
|
Pushing to `main` deploys to production — [deployment.md](deployment.md).
|