{"id":18888147,"url":"https://github.com/consol/super-simple-storage-solution","last_synced_at":"2026-02-24T13:30:14.016Z","repository":{"id":72844673,"uuid":"501166211","full_name":"ConSol/super-simple-storage-solution","owner":"ConSol","description":null,"archived":false,"fork":false,"pushed_at":"2023-10-08T15:47:18.000Z","size":547,"stargazers_count":2,"open_issues_count":5,"forks_count":0,"subscribers_count":3,"default_branch":"main","last_synced_at":"2024-12-31T05:28:54.144Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ConSol.png","metadata":{"files":{"readme":"README.adoc","changelog":null,"contributing":null,"funding":null,"license":null,"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}},"created_at":"2022-06-08T08:36:32.000Z","updated_at":"2023-09-08T18:35:13.000Z","dependencies_parsed_at":"2024-11-08T07:42:40.029Z","dependency_job_id":"06b3d8d1-27b8-4897-ba8c-9906c8d611ff","html_url":"https://github.com/ConSol/super-simple-storage-solution","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ConSol%2Fsuper-simple-storage-solution","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ConSol%2Fsuper-simple-storage-solution/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ConSol%2Fsuper-simple-storage-solution/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ConSol%2Fsuper-simple-storage-solution/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ConSol","download_url":"https://codeload.github.com/ConSol/super-simple-storage-solution/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":239859562,"owners_count":19708863,"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":[],"created_at":"2024-11-08T07:42:29.517Z","updated_at":"2026-02-24T13:30:13.925Z","avatar_url":"https://github.com/ConSol.png","language":"Java","readme":":listing-caption: Listing\n:experimental:\n:toc:\n= Super Simple Storage Solution (S4)\n\n== Quick Facts\n\n[cols=\"1,1,1,1\"]\n|===\n| Service Name | URL | Username | Password\n| `rest-api` (Swagger-documentation) | http://localhost:8080/q/swagger-ui | N/A | N/A\n| `aggregator` | http://localhost:8081 | N/A | N/A\n| postgres | localhost:5432 | postgres | postgres\n| pgadmin4 (UI for postgres database) | http://localhost:8091 | \\pgadmin4@pgadmin.org | pgadmin4\n| Artemis (Web-console) | http://localhost:8161/console | artemis | artemis\n| Artemis (AMQP-Port) | localhost:5671 | N/A | N/A\n| Grafana (Monitoring) | http://localhost:3000 | grafana | grafana\n| Jaeger (Tracing) | http://localhost:16686 | N/A | N/A\n| Kibana (Log-Aggregation) | http://localhost:5601 | N/A | N/A\n|===\n\n== Introduction\n\nThis is a sample project that allows uploading files through multiple HTTP requests.\n\nIts aim is not to implement a complex service, but to show how we can work with quarkus and how we can implement certain concepts.\n\nAs such, the discussion of the business use case will be short, and we will take a deeper look at the features used.\n\n== Architecture\n\nS4 currently consists of two microservices:\n\n* one microservice providing the REST API (we will call this microservice `_rest-api_`), and\n* one microservice triggered through a messaging system (https://activemq.apache.org/components/artemis/:[ActiveMQ Artemis] through https://www.amqp.org/:[AMQP]) to aggregate upload parts into a final, downloadable file (we will call this microservice `_aggregator_`).\n\n=== REST API Usage\n\nThe idea is that users can upload one file through multiple parts. Each part can then be transmitted in a separate HTTP request. If an upload is transmitted in `N` parts, the whole upload will take `N + 2` requests:\n\n* One request to start the upload. The response of this request contains an `id`, which is used to reference the upload in subsequent requests. We will call this request `_startUpload_`.\n* `N` part-uploads. The `partNumbers` have to be numbered from `1` to `N`. We will call those requests `_addPart_`.\n* One request to tell S4 how many parts the whole upload has. We will call this request `_setTotalParts_`.\n\nThe `startUpload` request has to be called first. All other requests (`addPart(...)` as well as `setTotalParts`) can happen in any order.\n\nThe parts are stored in a https://www.postgresql.org/:[PostgreSQL] database. When all parts have been transmitted, the `rest-api` sends a message over the messaging system to the `aggregator`, which then fetches all parts form the database, aggregates them to one file, and writes them back to the database.\n\n=== Sequence diagram\n\nFollowing is a sequence diagram, showing the core functionality of S4. This is mostly the happy path. Furthermore, some side functionalities (like deletion of uploads, and download of parts) are not shown.\n\n.Sequence diagram for the core functionality of S4\n[plantuml, target=diagram-sequence, format=png]\n----\n@startuml\nskinparam sequenceArrowThickness 2\nskinparam sequenceArrowColor Black\nactor Alice\n\n== Start Upload ==\nAlice -\u003e \"rest-api\": \"\"POST /uploads\"\" to start upload\ndatabase PostgreSQL\n\"rest-api\" -\u003e PostgreSQL: writes data\n\"rest-api\" \u003c- PostgreSQL\nAlice \u003c- \"rest-api\": responds with \"\"id\"\" of the upload\n\n\n== Content Upload ==\nAlice -[#Blue]\u003e \"rest-api\": \"\"POST /uploads/{id}/parts\"\" to upload part\nactivate \"rest-api\" #Blue\n\"rest-api\" -[#Blue]\u003e PostgreSQL: writes data\nactivate PostgreSQL #Blue\n\nAlice -[#Red]\u003e \"rest-api\": \"\"POST /uploads/{id}/totalParts\"\" to set the \"\"totalParts\"\" of the upload\nactivate \"rest-api\" #Red\n\"rest-api\" -[#Red]\u003e PostgreSQL: writes data\nactivate PostgreSQL #Red\n\nAlice -[#Green]\u003e \"rest-api\": \"\"POST /uploads/{id}/parts\"\" to upload part\nactivate \"rest-api\" #Green\n\"rest-api\" -[#Green]\u003e PostgreSQL: writes data\nactivate PostgreSQL #Green\n\n\"rest-api\" \u003c[#Green]- PostgreSQL\ndeactivate PostgreSQL #Green\nAlice \u003c-[#Green]- \"rest-api\": response to \"\"uploadPart\"\"\ndeactivate \"rest-api\" #GREEN\n\n\"rest-api\" \u003c[#Red]- PostgreSQL\ndeactivate PostgreSQL #Red\nAlice \u003c-[#Red]- \"rest-api\": response to \"\"totalParts\"\"\ndeactivate \"rest-api\" #Red\n\n\"rest-api\" \u003c[#Blue]- PostgreSQL\ndeactivate PostgreSQL #Blue\nAlice \u003c-[#Blue]- \"rest-api\": response to \"\"uploadPart\"\"\ndeactivate \"rest-api\" #Blue\n\n== Processing ==\n\"rest-api\" -\u003e \"rest-api\": detects that all parts are present\n\nqueue ActiveMQ\n\"rest-api\" --\u003e ActiveMQ: Upload \"\"id\"\" can be processed\n\nActiveMQ --\u003e accumulator: Upload \"\"id\"\" can be processed\n\naccumulator -\u003e PostgreSQL: loads parts\nactivate PostgreSQL #Black\naccumulator \u003c- PostgreSQL\ndeactivate PostgreSQL #Black\n\naccumulator -\u003e accumulator: aggregates parts\n\naccumulator -\u003e PostgreSQL: writes result back\nactivate PostgreSQL #Black\naccumulator \u003c- PostgreSQL\ndeactivate PostgreSQL #Black\n\n== Download ==\n\nAlice -\u003e \"rest-api\": \"\"GET /uploads/{id}/content\"\" to download the file\n\"rest-api\" -\u003e PostgreSQL: loads data\nactivate PostgreSQL #Black\n\"rest-api\" \u003c- PostgreSQL\ndeactivate PostgreSQL #black\nAlice \u003c- \"rest-api\": responds with file\n@enduml\n----\n\n== Project setup\n\nThis chapter discusses the project setup, mainly the folder structure and gives a rational as to why it is the way it is. Keep in mind that this is a sample project. in a real project, we can extract-out parts in, for example, separate repositories.\n\n== Build-System Setup: Maven\n\nAs build system, we are using https://maven.apache.org/:[Apache Maven] in a multi-module-setup. Since the folder structure is quite complex, we will focus on the parts relevant to maven in this chapter.\n\nThe following listing shows the directories that represent maven modules. each directory contains a `pom.xml` file.\n\n.Folder structure of the S4 project\n----\nsuper-simple-storage-solution\n├── bom\n├── commons\n│   ├── correlation\n│   ├── correlation-http\n│   ├── http-exceptions\n│   ├── micrometer-jvm-extras\n│   ├── opentracing-amqp\n│   └── opentracing-messaging\n└── services\n    ├── aggregator\n    └── rest-api\n----\n\n=== Naming conventions\n\nEach module's `artifactId` is constructed by following rules:\n\n* The root module is called `s4`\n* Each module adds its path from the root module as suffix to the name, with hierarchy levels represented by dashes (`-`)\n* If a module contains submodules, it appends `-parent` to its name.\n\nSo for example, the module residing in folder `super-simple-storage-solution/service/aggregator` is named `s4-services-aggregator`. The module residing in `super-simple-storage-solution/commons` is called `s4-commons-parent`.\n\nAside from the `artifactId`, each module has a name. The rules here are:\n\n* the root is called `S4`\n* ach module adds its path from the root module as suffix to the name, with hierarchy levels represented by `::`, surrounded by blanks\n* The names are capitalized where applicable. Dashes in folder names are replaced with blanks. The names can also be extended\n\nSo for example, the module residing in `super-simple-storage-solution/services/rest-api` has the name `S4 {two-colons} Services {two-colons} REST API`. The module residing in `super-simple-storage-solution/commons/micrometer-jvm-extras` is called `S4 {two-colons} Commons {two-colons} MicroMeter JVM Extras`.\n\nIf not otherwise noted, we will reference the modules by their name, not their `artifactId`.\n\n=== Dependency structure\n\nAll modules use the next module in the directory hierarchy as their parent. So `S4 {two-colons} Commons {two-colons} Correlation` 's parent is `S4 {two-colons} Commons`, while `S4 {two-colons} Commons` ' parent is `S4`. The only exception to this rule is the `S4 {two-colons} BOM` module. It is the direct parent of the `S4` module and thus the root of this project's dependency structure. Net following figure visualizes this structure.\n\n.Sequence diagram for the core functionality of S4\n[plantuml, target=diagram-usecase, format=png]\n----\n@startuml\n(S4) -up-|\u003e (S4 :: BOM)\n\n(S4 :: Services) -up-|\u003e (S4)\n(S4 :: Commons) -up-|\u003e (S4)\n\n\n(S4 :: Services :: Aggregator) -up-|\u003e (S4 :: Services)\n(S4 :: Services :: REST API) -up-|\u003e (S4 :: Services)\n\n(S4 :: Commons :: Correlation) -up-|\u003e (S4 :: Commons)\n(S4 :: Commons :: Correlation HTTP) -up-|\u003e (S4 :: Commons)\n(S4 :: Commons :: HTTP exceptions) -up-|\u003e (S4 :: Commons)\n(S4 :: Commons :: Opentracing messaging) -up-|\u003e (S4 :: Commons)\n(S4 :: Commons :: Opentracing AMQP)  -up-|\u003e (S4 :: Commons)\n@enduml\n----\n\n=== Semantics of the parent modules\n\nWe will now take a high-level view of the parent modules, i.e. `S4 {two-colons} BOM`, `S4`, `S4 {two-colons} Commons` and `S4 {two-colons} Services`.\n\n==== Module `S4 {two-colons} BOM`\n\nFile: file:///bom/pom.xml:[bom/pom.xml]\n\nThis is the https://reflectoring.io/maven-bom/:[Bill of Materials] (short _BOM_) of the project. All dependency versions (including the version of all submodules) are defined here. It acts as a central definition for all dependencies and plugins used. As such, it contains\n\n* a `\u003cproperties\u003e` section with one property per version for a dependency and/or plugin,\n* a `\u003cpluginManagement\u003e` section with all plugin definitions,\n* a `\u003cplugins\u003e` section, activating plugins needed on all modules,\n* a `\u003cdependencyManangement\u003e` section with all dependency definitions, and\n* a `depdendencies\u003e` section with common dependencies over all projects.\n\nThe plugins in the `\u003cpluginManagement\u003e` section are generally ordered in the order they are executed. For example, `maven-compiler-plugin` and `quarkus-maven-plugin` are executed during compile phase, while `maven-checkstyle-plugin` and `maven-surefire-plugin` are executed during test phase.\n\nThe `\u003cplugins\u003e` section includes plugins used by all modules. Those are currently three: the `maven-compiler-plugin`, the `maven-checkstyle-plugin` and the `maven-surefire-plugin`. The plugins are ordered in the same manner as the plugins in the `\u003cpluginManagement\u003e`-section are.\n\nThe dependencies in the `\u003cdependencyManangement\u003e` section are ordered in the following way:\n\n1. Quarkus main dependencies\n2. Quarkiverse dependencies (currently none)\n3. Quarkus-dependencies from `S4 {two-colons} Commons`\n4. Non-quarkus dependencies\n5. Test dependencies\n6. Annotation processors\n\nIn the `\u003cdependencies\u003e`-section, two dependencies are activated globally: `mapstruct` and `lombok`. Those dependencies are available in all submodules.","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fconsol%2Fsuper-simple-storage-solution","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fconsol%2Fsuper-simple-storage-solution","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fconsol%2Fsuper-simple-storage-solution/lists"}