{"id":48836616,"url":"https://github.com/andrei-punko/articles-backend-app","last_synced_at":"2026-04-14T23:36:11.193Z","repository":{"id":105077937,"uuid":"215827139","full_name":"andrei-punko/articles-backend-app","owner":"andrei-punko","description":"Full-fledged Spring Boot backend application (Test task)","archived":false,"fork":false,"pushed_at":"2026-01-26T17:16:30.000Z","size":643,"stargazers_count":4,"open_issues_count":0,"forks_count":4,"subscribers_count":1,"default_branch":"master","last_synced_at":"2026-01-27T04:12:41.169Z","etag":null,"topics":["gatling","jpa","rest-api","spock","spock-tests","spring-boot","spring-boot-3","spring-boot-application","spring-data","spring-rest","spring-security","stomp","swagger","web-socket-server"],"latest_commit_sha":null,"homepage":"","language":"Java","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/andrei-punko.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":"2019-10-17T15:33:46.000Z","updated_at":"2026-01-26T17:17:05.000Z","dependencies_parsed_at":"2024-01-05T23:25:12.356Z","dependency_job_id":"c1561f3a-0778-48e6-991f-7e4d23868237","html_url":"https://github.com/andrei-punko/articles-backend-app","commit_stats":null,"previous_names":[],"tags_count":0,"template":true,"template_full_name":null,"purl":"pkg:github/andrei-punko/articles-backend-app","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andrei-punko%2Farticles-backend-app","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andrei-punko%2Farticles-backend-app/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andrei-punko%2Farticles-backend-app/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andrei-punko%2Farticles-backend-app/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/andrei-punko","download_url":"https://codeload.github.com/andrei-punko/articles-backend-app/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andrei-punko%2Farticles-backend-app/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31820118,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-14T18:05:02.291Z","status":"ssl_error","status_checked_at":"2026-04-14T18:05:01.765Z","response_time":153,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":["gatling","jpa","rest-api","spock","spock-tests","spring-boot","spring-boot-3","spring-boot-application","spring-data","spring-rest","spring-security","stomp","swagger","web-socket-server"],"created_at":"2026-04-14T23:36:08.745Z","updated_at":"2026-04-14T23:36:11.181Z","avatar_url":"https://github.com/andrei-punko.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Test task (Apple): Spring Boot backend app\r\n\r\n[![Java CI](https://github.com/andrei-punko/articles-backend-app/actions/workflows/maven.yml/badge.svg)](https://github.com/andrei-punko/articles-backend-app/actions/workflows/maven.yml)\r\n[![Coverage](.github/badges/jacoco.svg)](https://github.com/andrei-punko/articles-backend-app/actions/workflows/maven.yml)\r\n[![Branches](.github/badges/branches.svg)](https://github.com/andrei-punko/articles-backend-app/actions/workflows/maven.yml)\r\n[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)\r\n\r\n## Requirements\r\n\r\nThis should be purely a REST endpoints backend application without UI, but feel free to attach Swagger UI for\r\nconvenience.\r\n\r\n- Build tool: Maven\r\n- DB: Postgres\r\n- Source Control: GitHub (public)\r\n- Application name: articles-backend-app\r\n\r\nApplication must be implemented using Spring Data (JPA/Hibernate) layer for communication with DB.\r\n\r\nSQL queries should not be used, JPA Repositories and Entities should be used instead.\r\n\r\nApplication should have no authentication.\r\n\r\nApplication will allow to create, update and delete Articles.\r\n\r\nApplication will have `authors` entity with the following properties:\r\n\r\n- First Name\r\n- Last Name\r\n\r\n**Article** will have the following properties:\r\n\r\nEditable properties (updatable via endpoints):\r\n\r\n- **Title** , text limited to 100 characters\r\n- **Summary** , text limited to 255 characters\r\n- **Text** , text with no specific limit\r\n- **Author:** relation with the **authors** table **. ONLY** updatable at creation. Should not be updatable after\r\n  Article has been created\r\n\r\nNon-Editable properties, updated automatically by Application:\r\n\r\n- Date Created\r\n- Date Updated\r\n\r\nApplication should expose REST endpoints that allow the following operations:\r\n\r\n- Create new Article\r\n- Update existing Article\r\n    - Only one property at the time should be updatable.\r\n- Delete existing Article\r\n- Retrieve all articles in the system sorted by title\r\n\r\nThe Article JSON Payload returned by endpoint(s) must contain all properties of Article listed above.\r\n\r\nBusiness Logic layer of the Application must enforce the following rules:\r\n\r\n- Non-editable properties cannot be updated/set via the create or update endpoints\r\n- Article cannot be created or update with empty Title or Text or Author ID\r\n- Article cannot be created with specified author id that does not exist in the **authors** table\r\n\r\nAny business logic constraint violation or any runtime error should return an HTTP 500 error with short description.  \r\n(Guys confirmed that 400 errors could be used instead when needed as more appropriate)\r\n\r\nThe implementation must contain adequate unit tests to cover business requirements and edge cases such as missing\r\narguments etc.\r\n\r\nApplication must build and produce an executable jar containing all dependencies.\r\n\r\nThe **authors** table should not be updatable via endpoints. Feel free to populate it with an arbitrary data via SQL.\r\n\r\n## Additional requirements (added by me)\r\n\r\n- Operation for getting existing Article\r\n- Add pagination support for `Retrieve all articles` operation\r\n- Operations for getting authors\r\n\r\n## Prerequisites\r\n\r\n- Maven 3\r\n- JDK 21\r\n\r\n## Build an application:\r\n\r\n```bash\r\nmvn clean install\r\n```\r\n\r\nResult `jar` placed into [target](target) folder\r\n\r\n## Build Docker image with application inside:\r\n\r\n```bash\r\ndocker build ./ -t articles-backend-app\r\n```\r\n\r\nResult Docker image has name `articles-backend-app` as mentioned in command\r\n\r\n## Start application using Maven (vs in-memory DB H2):\r\n\r\n    mvn spring-boot:run -Dspring-boot.run.arguments=\"\\\r\n    --spring.datasource.url=jdbc:h2:mem:testdb \\\r\n    --spring.datasource.username=sa \\\r\n    --spring.datasource.password=password \\\r\n    --spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.H2Dialect\"\r\n\r\nOr next way, using `dev` spring profile:\r\n\r\n    mvn spring-boot:run -Dspring-boot.run.arguments=--spring.profiles.active=dev\r\n\r\n## Start application by running executable jar (vs in-memory DB H2):\r\n\r\n    java -jar target/articles-backend-app-0.0.1-SNAPSHOT.jar \\\r\n     --spring.datasource.url=jdbc:h2:mem:testdb \\\r\n     --spring.datasource.username=sa \\\r\n     --spring.datasource.password=password \\\r\n     --spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.H2Dialect\r\n\r\nOr next way, using `dev` spring profile:\r\n\r\n    java -jar target/articles-backend-app-0.0.1-SNAPSHOT.jar \\\r\n     --spring.profiles.active=dev\r\n\r\n## Start Docker containers (application \u0026 Postgres DB) using existing images:\r\n\r\n    docker-compose up\r\n\r\n## Build images, force recreate and start Docker containers (application \u0026 Postgres DB):\r\n\r\n    docker-compose up --build --force-recreate\r\n\r\n## Link for quick check:\r\n\r\nhttp://localhost:8099/api/v1/articles\r\n\r\n## Swagger documentation:\r\n\r\nhttp://localhost:8099/swagger-ui.html\r\n\r\n## Check logs when start without Docker:\r\n\r\n    less ./logs/spring-boot-logger.log\r\n\r\n## Check logs when start using Docker:\r\n\r\n    docker exec -it articles-backend-app sh\r\n    less /logs/spring-boot-logger.log\r\n\r\n## Useful CURL commands\r\n\r\n### New article addition:\r\n\r\n```bash\r\ncurl -i -X POST -H \"Accept: application/json\" -H \"Content-Type: application/json\" -d '{ \"title\": \"Some tittle\", \"text\": \"Some text\", \"author\": { \"id\": 1 } }' http://localhost:8099/api/v1/articles\r\n```\r\n\r\n### Get existing article:\r\n\r\n```bash\r\ncurl -i http://localhost:8099/api/v1/articles/1\r\n```\r\n\r\n### Update existing article:\r\n\r\n```bash\r\ncurl -i -X PATCH -H \"Accept: application/json\" -H \"Content-Type: application/json\" -d '{ \"title\": \"Another tittle\" }' http://localhost:8099/api/v1/articles/2\r\n```\r\n\r\n### Get list of all articles:\r\n\r\n```bash\r\ncurl -i http://localhost:8099/api/v1/articles\r\n```\r\n\r\n### Get list of articles with pagination support:\r\n\r\n```bash\r\ncurl -i 'http://localhost:8099/api/v1/articles?size=2\u0026page=4\u0026sort=author.firstName,DESC'\r\n```\r\n\r\n### Deletion of article:\r\n\r\n```bash\r\ncurl -i -X DELETE http://localhost:8099/api/v1/articles/1\r\n```\r\n\r\n### Get existing author:\r\n\r\n```bash\r\ncurl -i http://localhost:8099/api/v1/authors/4\r\n```\r\n\r\n### Get list of all authors:\r\n\r\n```bash\r\ncurl -i http://localhost:8099/api/v1/authors\r\n```\r\n\r\n## Run functional tests:\r\n\r\n    cd func-test\r\n    ./gradlew clean build\r\n\r\nCheck Spock report at `func-test/build/spock-reports/index.html`\r\n\r\n## Run performance tests:\r\n\r\nBased on https://docs.gatling.io/\r\n\r\n### Gradle-based:\r\n\r\n    cd load-test\r\n    ./gradlew clean build\r\n    java -Dlogback.configurationFile=logback-gatling.xml -jar ./build/libs/articles-backend-app-load-test-fat.jar -s=load.WebAppLoadSimulation -rf=./build/reports/gatling\r\n\r\nCheck report at `./load-test/build/reports/gatling/`\r\n\r\n### Or Maven-based:\r\n\r\n    cd load-test\r\n    mvn gatling:test -Dlogback.configurationFile=logback-gatling.xml\r\n\r\nCheck report at `./load-test/target/gatling/`\r\n\r\nUseful article on Habr: https://habr.com/ru/companies/tbank/articles/344818/\r\n\r\n## Check Web-Sockets functionality:\r\n\r\nJust open page http://localhost:8099 and click `Connect`.  \r\nCheck heartbeat logs in browser developer console.\r\n\r\n## Start monitoring stack (Prometheus \u0026 Grafana):\r\n\r\nCheck [Monitoring README](monitoring/README.MD) with details\r\n\r\n## Start ELK stack with logs providing by Filebeat:\r\n\r\nCheck [ELK README](elk-filebeat/README.MD) with details\r\n\r\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fandrei-punko%2Farticles-backend-app","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fandrei-punko%2Farticles-backend-app","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fandrei-punko%2Farticles-backend-app/lists"}