{"id":29354239,"url":"https://github.com/toxicsnail/user-bulkupdater","last_synced_at":"2026-05-20T10:13:47.355Z","repository":{"id":303087671,"uuid":"1014199056","full_name":"ToxicSnail/User-BulkUpdater","owner":"ToxicSnail","description":"Synchronise the company-wide user catalogue in one shot: upload a file, let the service create new users, update existing ones, and log every error line for later review.","archived":false,"fork":false,"pushed_at":"2025-07-05T15:29:17.000Z","size":388,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-07-05T16:39:34.565Z","etag":null,"topics":["api","java-17","postgresql","spring"],"latest_commit_sha":null,"homepage":"","language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ToxicSnail.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-07-05T08:39:01.000Z","updated_at":"2025-07-05T09:16:51.000Z","dependencies_parsed_at":"2025-07-05T16:54:22.497Z","dependency_job_id":null,"html_url":"https://github.com/ToxicSnail/User-BulkUpdater","commit_stats":null,"previous_names":["toxicsnail/user-bulkupdater"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/ToxicSnail/User-BulkUpdater","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ToxicSnail%2FUser-BulkUpdater","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ToxicSnail%2FUser-BulkUpdater/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ToxicSnail%2FUser-BulkUpdater/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ToxicSnail%2FUser-BulkUpdater/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ToxicSnail","download_url":"https://codeload.github.com/ToxicSnail/User-BulkUpdater/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ToxicSnail%2FUser-BulkUpdater/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":264384390,"owners_count":23599612,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["api","java-17","postgresql","spring"],"created_at":"2025-07-09T03:11:50.352Z","updated_at":"2026-05-20T10:13:47.349Z","avatar_url":"https://github.com/ToxicSnail.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"# User-BulkUpdater\n\n\n\u003e *A Spring Boot micro‑service that keeps your user directory in sync by processing uploads.*\n\n---\n\n## Table of Contents\n\n1. [Problem statement](#problem-statement)\n2. [Key features](#key-features)\n3. [Upload file requirements](#upload-file-requirements)\n4. [Typical work‑flow](#typical-work-flow)\n5. [REST API](#rest-api)\n6. [Running locally](#running-locally)\n7. [Project structure](#project-structure)\n8. [Contributing](#contributing)\n\n---\n\n## Problem statement\n\nThe 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.\n\nThe functional and non‑functional requirements are taken from the original [assignment](README_RU.md)\n\n## Key features\n\n* Upload a user list via **`/files`**.\n* Trigger asynchronous processing via **`/files/{fileId}/processing`**.\n* Inspect a single file (status \u0026 aggregated counters) or the whole history via **`/files/{id}`** and **`/files/statistics`**.\n* Drill down into validation errors row‑by‑row via **`/files/{fileId}/statistics`**.\n* Browse the current user catalogue with flexible filtering via **`/clients`**.\n* Four processing statuses are tracked:\n\n  * `NEW` – file is saved but not yet processed.\n  * `IN_PROGRESS` – background job is running.\n  * `DONE` – finished successfully, even if some rows failed.\n  * `FAILED` – fatal error, job aborted.\n\n## Upload file requirements\n\nThe 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.\n\n| # | Field       | Required | Rules (short)                                                   |\n| - | ----------- | -------- | --------------------------------------------------------------- |\n| 1 | First name  | ✔        | Cyrillic, first letter upper‑case, 3‑50 chars                   |\n| 2 | Last name   | ✔        | Same as first name                                              |\n| 3 | Middle name | –        | Same charset rules, optional                                    |\n| 4 | E‑mail      | ✔        | Standard pattern, domain `shift.com` or `shift.ru`, ≤ 100 chars |\n| 5 | Phone       | ✔        | Digits, starts with `7`, unique, length 11                      |\n| 6 | Birth date  | ✔        | `yyyy‑MM‑dd`, age ≥ 18                                          |\n\n\u003e **Example**\n\u003e\n\u003e ```csv\n\u003e Иванов,Иван,Иванович,ivan.ivanov@shift.com,79161234567,1990-05-15\n\u003e ```\n\n## Typical work‑flow\n\n1. **Upload** a file – receive `fileId`.\n2. **Start processing** → `IN_PROGRESS`.\n3. Poll **statistics** until the status becomes `DONE` or `FAILED`.\n4. If `errorProcessedLinesCount \u003e 0`, fetch the **detailed statistics**, fix bad rows and repeat.\n5. Verify the result through **`/clients`**.\n\nSequence and component diagrams are located in `images/` (see `save_file.png`, `process_file.png`).\n\n## REST API\n\nThe full OpenAPI description lives in [`api/openapi.yaml`](documentation/api/openapi.yaml). A shortened cheat‑sheet:\n\n| Method | Path                         | Purpose                      |\n| ------ | ---------------------------- | ---------------------------- |\n| POST   | `/files`                     | Upload a CSV file            |\n| POST   | `/files/{fileId}/processing` | Launch async processing      |\n| GET    | `/files/{fileId}`            | File meta \u0026 counters         |\n| GET    | `/files/statistics`          | List of all files (filtered) |\n| GET    | `/files/{fileId}/statistics` | Row‑level error list         |\n| GET    | `/clients`                   | Search current users         |\n\n\u003e **Versioning** – the base path can be prefixed with `/api/v1` if you enable it in `application.yml`; the controller mappings are isolated so both styles can live side‑by‑side.\n\n## Running locally\n\n### Prerequisites\n\n* JDK 17+\n* Docker \u0026 Docker Compose\n* `make` or Gradle wrapper (`./gradlew`)\n\n### Quick start\n\n```bash\n#run containers\ndocker compose up\n\n# build the artefact without tests\n./gradlew clean build -x test\n\n# start the stack (app + PostgreSQL)\n./gradlew bootRun      # or:  docker compose up --build\n\n# open swagger‑ui\nhttp://localhost:8080/swagger-ui.html\n```\n\nThe default DB connection parameters are configured in `application.yml`. You can override them via environment variables.\n\n## Project structure\n\n```\nbackend/\n ├─ src/main/java/ru/shift/userimporter\n │   ├─ api        # REST controllers, DTOs and mappers\n │   ├─ config     # some configs\n │   ├─ core       # business logic \u0026 domain models\n │   └─ infrastructure\n ├─ api/openapi.yaml\n └─ docker-compose.yml\n```\n\n---\n\n© 2025 Gorky Kirill – MIT licence\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftoxicsnail%2Fuser-bulkupdater","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftoxicsnail%2Fuser-bulkupdater","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftoxicsnail%2Fuser-bulkupdater/lists"}