A Spring Boot micro‑service that keeps your user directory in sync by processing uploads.
- Problem statement
- Key features
- Upload file requirements
- Typical work‑flow
- REST API
- Running locally
- Project structure
- Contributing
The service receives a file with personal data, validates every row and then adds or updates users stored in PostgreSQL. All statistics about the processing session are persisted and exposed through the API so that a client can monitor progress and inspect errors.
The functional and non‑functional requirements are taken from the original assignment
-
Upload a user list via
/files. -
Trigger asynchronous processing via
/files/{fileId}/processing. -
Inspect a single file (status & aggregated counters) or the whole history via
/files/{id}and/files/statistics. -
Drill down into validation errors row‑by‑row via
/files/{fileId}/statistics. -
Browse the current user catalogue with flexible filtering via
/clients. -
Four processing statuses are tracked:
NEW– file is saved but not yet processed.IN_PROGRESS– background job is running.DONE– finished successfully, even if some rows failed.FAILED– fatal error, job aborted.
The file must be UTF‑8 without quotes and contain six columns in the order listed below. Full validation rules are summarised here – see the detailed document for edge cases.
| # | Field | Required | Rules (short) |
|---|---|---|---|
| 1 | First name | ✔ | Cyrillic, first letter upper‑case, 3‑50 chars |
| 2 | Last name | ✔ | Same as first name |
| 3 | Middle name | – | Same charset rules, optional |
| 4 | E‑mail | ✔ | Standard pattern, domain shift.com or shift.ru, ≤ 100 chars |
| 5 | Phone | ✔ | Digits, starts with 7, unique, length 11 |
| 6 | Birth date | ✔ | yyyy‑MM‑dd, age ≥ 18 |
Example
Иванов,Иван,Иванович,ivan.ivanov@shift.com,79161234567,1990-05-15
- Upload a file – receive
fileId. - Start processing →
IN_PROGRESS. - Poll statistics until the status becomes
DONEorFAILED. - If
errorProcessedLinesCount > 0, fetch the detailed statistics, fix bad rows and repeat. - Verify the result through
/clients.
Sequence and component diagrams are located in images/ (see save_file.png, process_file.png).
The full OpenAPI description lives in api/openapi.yaml. A shortened cheat‑sheet:
| Method | Path | Purpose |
|---|---|---|
| POST | /files |
Upload a CSV file |
| POST | /files/{fileId}/processing |
Launch async processing |
| GET | /files/{fileId} |
File meta & counters |
| GET | /files/statistics |
List of all files (filtered) |
| GET | /files/{fileId}/statistics |
Row‑level error list |
| GET | /clients |
Search current users |
Versioning – the base path can be prefixed with
/api/v1if you enable it inapplication.yml; the controller mappings are isolated so both styles can live side‑by‑side.
- JDK 17+
- Docker & Docker Compose
makeor Gradle wrapper (./gradlew)
#run containers
docker compose up
# build the artefact without tests
./gradlew clean build -x test
# start the stack (app + PostgreSQL)
./gradlew bootRun # or: docker compose up --build
# open swagger‑ui
http://localhost:8080/swagger-ui.htmlThe default DB connection parameters are configured in application.yml. You can override them via environment variables.
backend/
├─ src/main/java/ru/shift/userimporter
│ ├─ api # REST controllers, DTOs and mappers
│ ├─ config # some configs
│ ├─ core # business logic & domain models
│ └─ infrastructure
├─ api/openapi.yaml
└─ docker-compose.yml
© 2025 Gorky Kirill – MIT licence