├── .dive.yaml ├── .dockerignore ├── .editorconfig ├── .env.template ├── .gitattributes ├── .gitbook.yaml ├── .github ├── CODEOWNERS ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── docs.md │ └── question.md ├── chglog │ ├── CHANGELOG.tpl.md │ └── config.yml ├── codeql │ ├── codeql-config.yml │ └── custom-queries │ │ └── java │ │ └── .gitkeep ├── dependabot.yml ├── main.yml ├── release.yml ├── stale.yml ├── todo_workflows │ ├── build-without-koverVerify.yml │ ├── cli-continuous-integration.yml │ ├── cli-release.yml │ ├── kover-verify-pr.yml │ ├── rest-server-continuous-deployment.yml │ ├── rest-server-continuous-integration.yml │ ├── rest-server-create-infrastructure.yml │ └── rest-server-release.yml └── workflows │ ├── check.yml │ ├── codeql-analysis.yml.bak │ ├── codeql.yml │ ├── conventional-label.yml │ ├── deploy.yml │ ├── docs.yml │ ├── owasp-dep-check.yml │ ├── publish.yml │ └── release-build.yml ├── .gitignore ├── CHANGELOG.md ├── Jenkinsfile ├── LICENSE ├── README.md ├── SECURITY.md ├── TODO.md ├── buf.work.yaml ├── build.gradle.kts ├── buildSrc ├── build.gradle.kts ├── settings.gradle.kts └── src │ └── main │ └── kotlin │ ├── micro.apps.build.internal.convention-base.gradle.kts │ ├── micro.apps.build.internal.convention-benchmark.gradle.kts │ ├── micro.apps.build.internal.convention-quality.gradle.kts │ └── micro.apps.build.internal.convention-test.gradle.kts ├── cloudbuild.yaml ├── cog.toml ├── config ├── README.md ├── base │ ├── beam │ │ └── cronjob.yml │ ├── elastic │ │ ├── Dockerfile │ │ ├── README.md │ │ ├── config │ │ │ └── elasticsearch.yml │ │ ├── kustomization.yml │ │ ├── service.yml │ │ └── statefulset.yml │ ├── envoy │ │ ├── config │ │ │ ├── bootstrap.yaml │ │ │ ├── client_validation_context.yaml │ │ │ ├── clusters.yaml │ │ │ ├── endpoints.yaml │ │ │ ├── gateway-envoy.yaml │ │ │ ├── listeners.yaml │ │ │ ├── proxy_cert.yaml │ │ │ ├── routes.yaml │ │ │ └── upstream_validation_context.yaml │ │ ├── deployment.yaml │ │ ├── kustomization.yaml │ │ └── service.yaml │ ├── kconfig.yaml │ ├── kustomization.yaml │ ├── nifi │ │ ├── README.md │ │ ├── all.yml │ │ ├── ingress.yml │ │ ├── kustomization.yml │ │ ├── secret.yml │ │ ├── service.yml │ │ └── statefulset.yml │ ├── postgres │ │ ├── kustomization.yaml │ │ ├── scripts │ │ │ ├── create_databases.sh │ │ │ └── create_extensions.sh │ │ ├── service-headless.yaml │ │ ├── service.yaml │ │ └── statefulset.yaml │ └── service │ │ ├── greeting │ │ ├── deployment.yaml │ │ ├── kustomization.yaml │ │ └── service.yaml │ │ ├── kustomization.yaml │ │ └── spring │ │ ├── deployment.yaml │ │ ├── kustomization.yaml │ │ └── service.yaml ├── certs │ ├── .gitignore │ ├── README.md │ ├── ca-cert.cfg │ ├── ca-cert.pem │ ├── ca-key.pem │ ├── certs.sh │ ├── client-cert.cfg │ ├── client-cert.pem │ ├── client-ecdsa-cert.pem │ ├── client-ecdsa-key.pem │ ├── client-key.pem │ ├── proxy-cert.cfg │ ├── proxy-cert.pem │ ├── proxy-ecdsa-cert.pem │ ├── proxy-ecdsa-key.pem │ ├── proxy-key.pem │ ├── upstream-ca-cert.cfg │ ├── upstream-ca-cert.pem │ ├── upstream-ca-key.pem │ ├── upstream-cert.cfg │ ├── upstream-cert.pem │ ├── upstream-key.pem │ ├── upstream-localhost-cert.cfg │ ├── upstream-localhost-cert.pem │ └── upstream-localhost-key.pem └── envs │ ├── development │ ├── kustomization.yaml │ └── patches │ │ └── image-pull-policy-if-not-present.yaml │ ├── local │ └── kustomization.yaml │ ├── production │ ├── kustomization.yaml │ ├── patches │ │ ├── image-pull-policy-if-not-present.yaml │ │ └── resource_limit.yaml │ └── resources │ │ └── hpa.yaml │ └── staging │ ├── kustomization.yaml │ └── patches │ └── image-pull-policy-if-not-present.yaml ├── delivery └── envs │ ├── development.yaml │ ├── production.yaml │ └── staging.yaml ├── docker-compose.yml ├── docs ├── SUMMARY.md ├── adr │ ├── ADR.md │ └── monorepo-vs-multirepo.md ├── advanced │ ├── avro.md │ ├── buf.md │ ├── database.md │ ├── dataflow.md │ ├── dependencies.md │ ├── dgraph.md │ ├── gcs.md │ ├── github-actions.md │ ├── gitops.md │ ├── gradle.md │ ├── graphql.md │ ├── jenkins.md │ ├── kubernetes.md │ ├── makefile.md │ ├── opentelemetry.md │ ├── pubsub.md │ ├── redis.md │ ├── redpanda.md │ ├── spring.md │ └── svelte.md ├── awesome │ ├── awesome-gradle.md │ └── awesome-spring.md ├── community │ └── contribution.md ├── concepts │ ├── intro.md │ ├── monorepo.md │ ├── release.md │ ├── testing.md │ └── versioning.md ├── design │ ├── redis-crdt.md │ └── resiliency.md ├── devops │ ├── docker.md │ ├── gitops.md │ ├── rancher-desktop.md │ ├── security.md │ └── skaffold.md ├── faq │ ├── faq.md │ └── grpc.md ├── images │ ├── GitFlowDevelopBranch.png │ ├── GitFlowFeatureBranches.png │ ├── GitFlowFull.png │ ├── GitFlowHotfixBranch.png │ ├── GitFlowMasterBranch.png │ ├── GitFlowReleaseBranch.png │ ├── GitFlowWorkflowNoFork.png │ ├── GitFlowWorkflowNoFork.svg │ ├── active-active-behind.drawio.svg │ ├── active-active-behind.png │ ├── active-active-direct.drawio.svg │ ├── branches-overview.png │ ├── chat-app.png │ ├── dev-sec-ops.drawio.svg │ ├── end-to-end-google-cloud-devops-flow.png │ ├── git-flow-commands.png │ ├── gitflow-overview.webp │ ├── grpc-interface.svg │ ├── monolith-microservices.png │ ├── opentelemetry_architecture.webp │ ├── opentelemetry_java_instrument.webp │ ├── pipeline-develop.png │ ├── pipeline-feature.png │ └── pipeline-master.png ├── introduction │ ├── gitflow-usage.md │ ├── gitflow.md │ ├── installation.md │ ├── java-prerequisites.md │ ├── project-layout.md │ ├── roadmap.md │ └── why.md ├── notebooks │ ├── Comms.ipynb │ ├── Welcome to Kotlin Notebook!.ipynb │ └── sumo.ipynb └── recipes │ ├── recipe2.md │ └── streaming.md ├── gradle.properties ├── gradle.properties.global ├── gradle ├── libs.versions.toml └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── infra ├── Dockerfile ├── benthos │ ├── README.md │ ├── config.yaml │ ├── npidata.csv │ └── npidata.jsonl ├── bindings │ └── ca-certificates │ │ ├── my-corp-proxy.pem │ │ └── type ├── data │ └── README.md ├── db_scripts │ └── 1-schema.sql ├── dgraph.yml ├── grafana │ └── provisioning │ │ ├── dashboards │ │ └── sample-dashboard.json │ │ └── datasources │ │ └── redis.yaml ├── kafka │ ├── connectors │ │ └── .gitkeep │ ├── sql │ │ ├── data.sql │ │ ├── init.sql │ │ └── query-example.sql │ └── udf │ │ └── .gitkeep ├── mssql.yml ├── postgres.yml ├── redis.yml ├── redpanda-ksql.yml └── redpanda.yml ├── libs ├── avro │ ├── README.md │ ├── build.gradle.kts │ └── src │ │ ├── main │ │ └── kotlin │ │ │ └── micro │ │ │ └── libs │ │ │ └── avro │ │ │ ├── FieldExtractor.kt │ │ │ ├── RecordTransformer.kt │ │ │ ├── avpath │ │ │ └── RecordTraverser.kt │ │ │ ├── convert │ │ │ └── ConvertRecord.kt │ │ │ ├── schema.kt │ │ │ └── schema │ │ │ └── SchemaTraverser.kt │ │ └── test │ │ ├── kotlin │ │ └── micro │ │ │ └── libs │ │ │ └── avro │ │ │ ├── FieldExtractorSpec.kt │ │ │ ├── RecordTransformerSpec.kt │ │ │ ├── avpath │ │ │ └── RecordTraverserSpec.kt │ │ │ └── schema │ │ │ └── SchemaTraverserSpec.kt │ │ └── resources │ │ ├── account.avro │ │ └── account.avsc ├── core │ ├── README.md │ ├── build.gradle.kts │ └── src │ │ ├── main │ │ ├── kotlin │ │ │ └── micro │ │ │ │ └── apps │ │ │ │ └── core │ │ │ │ ├── compose.kt │ │ │ │ ├── extensions.kt │ │ │ │ ├── memorize.kt │ │ │ │ ├── tuples.kt │ │ │ │ └── utils.kt │ │ └── resources │ │ │ └── META-INF │ │ │ └── beans.xml │ │ └── test │ │ └── kotlin │ │ └── micro │ │ └── apps │ │ └── core │ │ ├── ExtensionsTest.kt │ │ ├── MemorizeCounterTest.kt │ │ └── MemorizeTest.kt ├── crypto │ ├── README.md │ ├── build.gradle.kts │ └── src │ │ ├── main │ │ └── kotlin │ │ │ └── micro │ │ │ └── apps │ │ │ └── crypto │ │ │ └── Cryptor.kt │ │ └── test │ │ ├── kotlin │ │ └── micro │ │ │ └── apps │ │ │ └── crypto │ │ │ └── CryptorTest.kt │ │ └── resources │ │ └── aead_keyset.json ├── graphql │ ├── README.md │ ├── build.gradle.kts │ └── src │ │ ├── main │ │ ├── kotlin │ │ │ └── micro │ │ │ │ └── apps │ │ │ │ └── service │ │ │ │ ├── config │ │ │ │ ├── GraphqlConfig.kt │ │ │ │ └── MessageSourceConfig.kt │ │ │ │ ├── directive │ │ │ │ ├── CapitalizeDirective.kt │ │ │ │ ├── LowercaseDirective.kt │ │ │ │ ├── SchemaDirective.kt │ │ │ │ ├── StringFormatDirective.kt │ │ │ │ ├── TrimDirective.kt │ │ │ │ └── UppercaseDirective.kt │ │ │ │ ├── exception │ │ │ │ ├── CustomGraphqlExceptionResolver.kt │ │ │ │ └── exceptions.kt │ │ │ │ └── validation │ │ │ │ └── EmailRule.kt │ │ └── resources │ │ │ └── graphql │ │ │ ├── schema.graphqls │ │ │ └── validation │ │ │ ├── ValidationMessages.properties │ │ │ └── ValidationMessages_tr.properties │ │ └── test │ │ └── kotlin │ │ └── micro │ │ └── apps │ │ └── service │ │ └── util │ │ └── ExtensionsTest.kt ├── grpc │ ├── README.md │ ├── build.gradle.kts │ └── src │ │ ├── main │ │ ├── kotlin │ │ │ └── micro │ │ │ │ └── apps │ │ │ │ └── service │ │ │ │ ├── interceptors │ │ │ │ └── UnknownStatusInterceptor.kt │ │ │ │ └── utils.kt │ │ └── resources │ │ │ └── META-INF │ │ │ └── beans.xml │ │ └── test │ │ └── kotlin │ │ └── micro │ │ └── apps │ │ └── service │ │ └── UtilsTest.kt ├── kbeam │ ├── README.md │ ├── build.gradle.kts │ └── src │ │ ├── main │ │ ├── kotlin │ │ │ └── micro │ │ │ │ └── apps │ │ │ │ └── kbeam │ │ │ │ ├── CoGroupByKey.kt │ │ │ │ ├── PViews.kt │ │ │ │ ├── ParDo.kt │ │ │ │ ├── Partition.kt │ │ │ │ ├── Pipe.kt │ │ │ │ ├── coders │ │ │ │ └── KryoCoder.kt │ │ │ │ ├── gcp │ │ │ │ ├── BigQuery.kt │ │ │ │ ├── PubSub.kt │ │ │ │ └── Spanner.kt │ │ │ │ ├── io │ │ │ │ └── File.kt │ │ │ │ └── transforms │ │ │ │ └── PubsubToAvro.kt │ │ └── resources │ │ │ └── shared_application.properties │ │ └── test │ │ ├── java │ │ └── micro │ │ │ └── apps │ │ │ └── kbeam │ │ │ ├── Entry.java │ │ │ ├── MyOptions.java │ │ │ └── SamplePipelineTest.java │ │ ├── kotlin │ │ └── micro │ │ │ └── apps │ │ │ └── kbeam │ │ │ ├── KBeamDSLTest.kt │ │ │ └── SamplePipelineKotlin.kt │ │ └── resources │ │ ├── application.properties │ │ └── data │ │ ├── country_codes.jsonl │ │ └── test.csv ├── kstream │ ├── README.md │ ├── build.gradle.kts │ └── src │ │ ├── main │ │ └── kotlin │ │ │ └── micro │ │ │ └── apps │ │ │ └── kstream │ │ │ ├── KSerdes.kt │ │ │ └── serializer │ │ │ ├── AbstractCryptoKafkaAvro4kDeserializer.kt │ │ │ ├── AbstractCryptoKafkaAvro4kSerDe.kt │ │ │ ├── AbstractCryptoKafkaAvro4kSerDeConfig.kt │ │ │ ├── AbstractCryptoKafkaAvro4kSerializer.kt │ │ │ ├── CryptoAvro4kSerde.kt │ │ │ ├── CryptoKafkaAvro4kDeserializer.kt │ │ │ ├── CryptoKafkaAvro4kDeserializerConfig.kt │ │ │ ├── CryptoKafkaAvro4kSerializer.kt │ │ │ └── CryptoKafkaAvro4kSerializerConfig.kt │ │ └── test │ │ └── kotlin │ │ └── micro │ │ └── apps │ │ └── kstream │ │ └── ExtensionsTest.kt ├── model │ ├── README.md │ ├── build.gradle.kts │ └── src │ │ ├── main │ │ ├── kotlin │ │ │ └── micro │ │ │ │ └── apps │ │ │ │ └── model │ │ │ │ └── models.kt │ │ └── resources │ │ │ └── META-INF │ │ │ └── beans.xml │ │ ├── test │ │ ├── kotlin │ │ │ └── micro │ │ │ │ └── apps │ │ │ │ └── model │ │ │ │ └── SerializationTest.kt │ │ └── resources │ │ │ └── data │ │ │ ├── pizzas.avro │ │ │ └── pizzas.avsc │ │ └── testFixtures │ │ └── kotlin │ │ └── micro │ │ └── apps │ │ └── model │ │ └── fixtures │ │ └── mock-person.kt ├── pipeline │ ├── README.md │ ├── build.gradle.kts │ └── src │ │ ├── main │ │ ├── kotlin │ │ │ └── micro │ │ │ │ └── apps │ │ │ │ └── pipeline │ │ │ │ ├── BaseBatchOptions.kt │ │ │ │ ├── BaseStreamingOptions.kt │ │ │ │ ├── coders │ │ │ │ └── .gitkeep │ │ │ │ ├── config │ │ │ │ └── .gitkeep │ │ │ │ ├── constants.kt │ │ │ │ ├── transforms │ │ │ │ └── .gitkeep │ │ │ │ └── utils.kt │ │ └── resources │ │ │ └── META-INF │ │ │ └── beans.xml │ │ ├── test │ │ └── kotlin │ │ │ └── micro │ │ │ └── apps │ │ │ └── pipeline │ │ │ └── UtilsTest.kt │ │ └── testFixtures │ │ └── kotlin │ │ └── micro │ │ └── apps │ │ └── pipeline │ │ └── PubsubHelper.kt ├── proto │ ├── README.md │ ├── build.gradle.kts │ └── src │ │ ├── main │ │ ├── kotlin │ │ │ └── micro │ │ │ │ └── apps │ │ │ │ └── proto │ │ │ │ ├── common │ │ │ │ └── v1 │ │ │ │ │ └── errors.kt │ │ │ │ └── util │ │ │ │ └── PersonFieldMasks.kt │ │ ├── proto │ │ │ ├── buf.lock │ │ │ ├── buf.yaml │ │ │ └── micro │ │ │ │ └── apps │ │ │ │ └── proto │ │ │ │ ├── account │ │ │ │ └── v1 │ │ │ │ │ └── account.proto │ │ │ │ ├── address │ │ │ │ └── v1 │ │ │ │ │ └── address.proto │ │ │ │ ├── common │ │ │ │ └── v1 │ │ │ │ │ └── common.proto │ │ │ │ ├── echo │ │ │ │ └── v1 │ │ │ │ │ └── echo.proto │ │ │ │ ├── keying │ │ │ │ └── v1 │ │ │ │ │ └── keying.proto │ │ │ │ ├── linking │ │ │ │ └── v1 │ │ │ │ │ └── linking.proto │ │ │ │ └── order │ │ │ │ └── v1 │ │ │ │ └── product.proto │ │ ├── resources │ │ │ └── META-INF │ │ │ │ └── beans.xml │ │ └── third_party_proto │ │ │ ├── buf.yaml │ │ │ └── validate │ │ │ └── validate.proto │ │ ├── test │ │ └── kotlin │ │ │ └── micro │ │ │ └── apps │ │ │ └── proto │ │ │ ├── account │ │ │ └── AccountKtTest.kt │ │ │ ├── common │ │ │ └── OrderKtTest.kt │ │ │ └── echo │ │ │ └── EchoKtTest.kt │ │ └── testFixtures │ │ └── kotlin │ │ └── micro │ │ └── apps │ │ └── proto │ │ ├── account │ │ └── fixtures │ │ │ └── mock-account.kt │ │ └── common │ │ └── fixtures │ │ └── mock-common.kt ├── spring │ ├── README.md │ ├── build.gradle.kts │ └── src │ │ ├── main │ │ └── kotlin │ │ │ └── micro │ │ │ └── apps │ │ │ └── service │ │ │ ├── CrudService.kt │ │ │ ├── DynamicLookupSerializer.kt │ │ │ ├── EventBus.kt │ │ │ ├── GlobalExceptionHandler.kt │ │ │ ├── exceptions.kt │ │ │ └── util │ │ │ └── serialization.kt │ │ └── test │ │ └── kotlin │ │ └── micro │ │ └── apps │ │ └── service │ │ └── UtilsTest.kt └── test │ ├── README.md │ ├── build.gradle.kts │ └── src │ └── testFixtures │ └── kotlin │ └── micro │ └── apps │ ├── model │ └── fixtures │ │ └── .gitkeep │ └── test │ └── tags.kt ├── package-list ├── pipelines ├── classifier │ ├── README.md │ ├── build.gradle.kts │ └── src │ │ ├── main │ │ ├── kotlin │ │ │ └── micro │ │ │ │ └── apps │ │ │ │ └── pipeline │ │ │ │ ├── ClassifierOptions.kt │ │ │ │ └── ClassifierPipeline.kt │ │ └── resources │ │ │ ├── config.prod.yaml │ │ │ ├── config.yaml │ │ │ ├── data │ │ │ ├── person.avro │ │ │ └── person.avsc │ │ │ └── logging.properties │ │ └── test │ │ ├── kotlin │ │ └── micro │ │ │ └── apps │ │ │ └── pipeline │ │ │ ├── ClassifierPipelineTest.kt │ │ │ ├── PubSubProducerTest.kt │ │ │ └── SerializationTest.kt │ │ └── resources │ │ ├── data │ │ ├── person.avro │ │ └── person.avsc │ │ └── logging.properties ├── ingestion │ ├── README.md │ ├── build.gradle.kts │ └── src │ │ ├── main │ │ ├── kotlin │ │ │ └── micro │ │ │ │ └── apps │ │ │ │ └── pipeline │ │ │ │ ├── IngestionOptions.kt │ │ │ │ ├── IngestionPipeline.kt │ │ │ │ ├── coders │ │ │ │ ├── AvroPersonCoder.kt │ │ │ │ └── KotlinAvroCoder.kt │ │ │ │ ├── config │ │ │ │ └── config.kt │ │ │ │ └── transforms │ │ │ │ ├── EnrichFn.kt │ │ │ │ └── PubsubToPerson.kt │ │ └── resources │ │ │ ├── config.prod.yaml │ │ │ ├── config.yaml │ │ │ ├── data │ │ │ ├── person.avro │ │ │ └── person.avsc │ │ │ └── logging.properties │ │ └── test │ │ ├── kotlin │ │ └── micro │ │ │ └── apps │ │ │ └── pipeline │ │ │ ├── IngestionPipelineTest.kt │ │ │ └── PubSubProducerTest.kt │ │ └── resources │ │ ├── data │ │ ├── person.avro │ │ └── person.avsc │ │ └── logging.properties └── wordcount │ ├── README.md │ ├── build.gradle.kts │ └── src │ ├── main │ ├── kotlin │ │ └── micro │ │ │ └── apps │ │ │ └── pipeline │ │ │ └── WordCountPipeline.kt │ └── resources │ │ ├── application.properties │ │ └── logging.properties │ └── test │ ├── kotlin │ └── micro │ │ └── apps │ │ └── pipeline │ │ ├── Junit5Test.kt │ │ └── WordCountPipelineTest.kt │ └── resources │ ├── application.properties │ ├── data │ ├── input.txt │ └── kinglear.txt │ └── logging.properties ├── scripts ├── add-keycloak-db.sh ├── karate-quarkus-demo-realm.json └── pubsub_functions.sh ├── services ├── account │ ├── README.md │ ├── build.gradle.kts │ └── src │ │ ├── graal │ │ └── reflect-config.json │ │ ├── main │ │ ├── kotlin │ │ │ └── micro │ │ │ │ └── apps │ │ │ │ └── service │ │ │ │ ├── AccountApplication.kt │ │ │ │ ├── config │ │ │ │ ├── README.md │ │ │ │ └── config.kt │ │ │ │ └── domain │ │ │ │ ├── account │ │ │ │ ├── AccountClient.kt │ │ │ │ └── AccountService.kt │ │ │ │ ├── address │ │ │ │ ├── AddressClient.kt │ │ │ │ └── AddressService.kt │ │ │ │ ├── echo │ │ │ │ ├── EchoClient.kt │ │ │ │ └── EchoService.kt │ │ │ │ └── order │ │ │ │ ├── ProductClient.kt │ │ │ │ └── ProductService.kt │ │ └── resources │ │ │ ├── config.prod.yaml │ │ │ ├── config.yaml │ │ │ └── simplelogger.properties │ │ └── test │ │ ├── kotlin │ │ └── micro │ │ │ └── apps │ │ │ └── service │ │ │ └── domain │ │ │ ├── account │ │ │ ├── AccountServiceResiliencyTest.kt │ │ │ └── AccountServiceTest.kt │ │ │ └── echo │ │ │ └── EchoServiceTest.kt │ │ └── resources │ │ ├── config.yaml │ │ └── simplelogger.properties ├── chat │ ├── README.md │ ├── build.gradle.kts │ └── src │ │ ├── main │ │ ├── kotlin │ │ │ └── micro │ │ │ │ └── apps │ │ │ │ └── service │ │ │ │ ├── ChatKotlinApplication.kt │ │ │ │ ├── Extensions.kt │ │ │ │ ├── controller │ │ │ │ ├── HtmlController.kt │ │ │ │ └── MessageResource.kt │ │ │ │ ├── repository │ │ │ │ ├── DomainModel.kt │ │ │ │ └── MessageRepository.kt │ │ │ │ └── service │ │ │ │ ├── MessageService.kt │ │ │ │ ├── PersistentMessageService.kt │ │ │ │ └── ViewModel.kt │ │ └── resources │ │ │ ├── application.properties │ │ │ ├── sql │ │ │ └── schema.sql │ │ │ ├── static │ │ │ ├── rsocket-core.js │ │ │ ├── rsocket-flowable.js │ │ │ ├── rsocket-types.js │ │ │ └── rsocket-websocket-client.js │ │ │ └── templates │ │ │ ├── chat.html │ │ │ └── chatrs.html │ │ └── test │ │ └── kotlin │ │ └── micro │ │ └── apps │ │ └── service │ │ ├── ChatKotlinApplicationTests.kt │ │ └── TestExtensions.kt ├── entity │ ├── API-TEST.md │ ├── HELP.md │ ├── README.md │ ├── build.gradle.kts │ ├── data │ │ └── employee.redis │ └── src │ │ ├── main │ │ ├── kotlin │ │ │ └── micro │ │ │ │ └── apps │ │ │ │ └── service │ │ │ │ ├── AppStartupRunner.kt │ │ │ │ ├── EntityApplication.kt │ │ │ │ ├── config │ │ │ │ ├── AppConfig.kt │ │ │ │ ├── RedisConfig.kt │ │ │ │ ├── SecurityConfig.kt │ │ │ │ ├── SwaggerConfig.kt │ │ │ │ ├── WebFluxConfig.kt │ │ │ │ └── properties.kt │ │ │ │ └── domain │ │ │ │ ├── account │ │ │ │ ├── AccountController.kt │ │ │ │ ├── AccountRepository.kt │ │ │ │ ├── AccountService.kt │ │ │ │ ├── ReativeAccountService.kt │ │ │ │ ├── extensions.kt │ │ │ │ ├── models.kt │ │ │ │ └── repositories.kt │ │ │ │ └── product │ │ │ │ └── .gitkeep │ │ └── resources │ │ │ ├── application-production.yml │ │ │ ├── application.yml │ │ │ ├── banner.txt │ │ │ └── logback-spring.xml │ │ └── test │ │ ├── kotlin │ │ └── micro │ │ │ └── apps │ │ │ └── service │ │ │ ├── EntityApplicationTest.kt │ │ │ ├── ProjectConfig.kt │ │ │ └── domain │ │ │ └── account │ │ │ ├── AccountControllerTests.kt │ │ │ ├── AccountRepositoryTests.kt │ │ │ ├── RedisDemoTests.kt │ │ │ └── mock-person.kt │ │ └── resources │ │ └── npidata.jsonl ├── greeting │ ├── .dockerignore │ ├── README.md │ ├── build.gradle.kts │ └── src │ │ ├── main │ │ ├── docker │ │ │ ├── Dockerfile.jvm │ │ │ ├── Dockerfile.legacy-jar │ │ │ ├── Dockerfile.native │ │ │ └── Dockerfile.native-distroless │ │ ├── kotlin │ │ │ └── micro │ │ │ │ └── apps │ │ │ │ └── service │ │ │ │ ├── GreetingApplication.kt │ │ │ │ ├── config │ │ │ │ └── AppConfig.kt │ │ │ │ ├── domain │ │ │ │ ├── account │ │ │ │ │ ├── Account.kt │ │ │ │ │ ├── AccountDTO.kt │ │ │ │ │ ├── AccountMapper.kt │ │ │ │ │ ├── AccountRepository.kt │ │ │ │ │ ├── AccountResource.kt │ │ │ │ │ └── AccountService.kt │ │ │ │ ├── echo │ │ │ │ │ └── EchoService.kt │ │ │ │ ├── fruit │ │ │ │ │ └── FruitResource.kt │ │ │ │ └── greeting │ │ │ │ │ ├── GreetingResource.kt │ │ │ │ │ └── GreetingService.kt │ │ │ │ └── util │ │ │ │ ├── IMapper.kt │ │ │ │ └── IService.kt │ │ └── resources │ │ │ ├── META-INF │ │ │ └── resources │ │ │ │ └── index.html │ │ │ └── application.yaml │ │ ├── native-test │ │ └── kotlin │ │ │ └── micro │ │ │ └── apps │ │ │ └── service │ │ │ └── NativeGreetingResourceIT.kt │ │ └── test │ │ ├── kotlin │ │ └── micro │ │ │ └── apps │ │ │ └── service │ │ │ ├── AccountServiceTest.kt │ │ │ ├── FruitResourceTest.kt │ │ │ ├── GreetingResourceTest.kt │ │ │ ├── MockTest.kt │ │ │ ├── MockedService.kt │ │ │ └── PropertiesTest.kt │ │ └── resources │ │ └── application.yaml ├── keying │ ├── README.md │ ├── build.gradle.kts │ └── src │ │ ├── main │ │ ├── kotlin │ │ │ └── micro │ │ │ │ └── apps │ │ │ │ └── service │ │ │ │ ├── KeyingApplication.kt │ │ │ │ ├── KeyingClient.kt │ │ │ │ ├── KeyingService.kt │ │ │ │ └── config │ │ │ │ ├── README.md │ │ │ │ └── config.kt │ │ └── resources │ │ │ ├── config.prod.yaml │ │ │ ├── config.yaml │ │ │ └── simplelogger.properties │ │ └── test │ │ ├── kotlin │ │ └── micro │ │ │ └── apps │ │ │ └── service │ │ │ └── domain │ │ │ └── echo │ │ │ └── KeyingServiceTest.kt │ │ └── resources │ │ ├── config.yaml │ │ └── simplelogger.properties ├── linking │ ├── README.md │ ├── build.gradle.kts │ └── src │ │ ├── main │ │ ├── kotlin │ │ │ └── micro │ │ │ │ └── apps │ │ │ │ └── service │ │ │ │ ├── LinkingApplication.kt │ │ │ │ ├── LinkingClient.kt │ │ │ │ ├── LinkingService.kt │ │ │ │ └── config │ │ │ │ ├── README.md │ │ │ │ └── config.kt │ │ └── resources │ │ │ ├── config.prod.yaml │ │ │ ├── config.yaml │ │ │ └── simplelogger.properties │ │ └── test │ │ ├── kotlin │ │ └── micro │ │ │ └── apps │ │ │ └── service │ │ │ └── domain │ │ │ └── echo │ │ │ └── KeyingServiceTest.kt │ │ └── resources │ │ ├── config.yaml │ │ └── simplelogger.properties ├── person │ ├── README.md │ ├── build.gradle.kts │ └── src │ │ ├── main │ │ ├── docker │ │ │ ├── Dockerfile.jvm │ │ │ ├── Dockerfile.legacy-jar │ │ │ ├── Dockerfile.native │ │ │ └── Dockerfile.native-distroless │ │ ├── kotlin │ │ │ └── micro │ │ │ │ └── apps │ │ │ │ └── service │ │ │ │ ├── GreetingResource.kt │ │ │ │ ├── Person.kt │ │ │ │ ├── PersonResource.kt │ │ │ │ ├── PersonService.kt │ │ │ │ ├── ScoreService.kt │ │ │ │ ├── ScoresNotAvailableException.kt │ │ │ │ └── models.kt │ │ └── resources │ │ │ ├── META-INF │ │ │ └── resources │ │ │ │ └── index.html │ │ │ ├── application.properties │ │ │ ├── import.sql │ │ │ ├── roles.properties │ │ │ ├── score.json │ │ │ └── users.properties │ │ ├── native-test │ │ └── kotlin │ │ │ └── micro │ │ │ └── apps │ │ │ └── service │ │ │ └── NativeGreetingResourceIT.kt │ │ └── test │ │ └── kotlin │ │ └── micro │ │ └── apps │ │ └── service │ │ ├── GreetingResourceTest.kt │ │ └── PersonResourceTest.kt ├── redis │ ├── README.md │ ├── build.gradle.kts │ └── src │ │ ├── data │ │ └── employee.redis │ │ └── main │ │ ├── kotlin │ │ └── micro │ │ │ └── apps │ │ │ └── service │ │ │ ├── AppStartupRunner.kt │ │ │ ├── PersonController.kt │ │ │ ├── RomsHashesApplication.kt │ │ │ ├── UserController.kt │ │ │ ├── config │ │ │ ├── RedisConfig.kt │ │ │ └── properties.kt │ │ │ ├── domain │ │ │ ├── account │ │ │ │ ├── AccountController.kt │ │ │ │ ├── AccountRepository.kt │ │ │ │ ├── AccountService.kt │ │ │ │ ├── extensions.kt │ │ │ │ ├── models.kt │ │ │ │ └── repositories.kt │ │ │ └── product │ │ │ │ └── .gitkeep │ │ │ ├── mock-person.kt │ │ │ ├── models.kt │ │ │ ├── people.kt │ │ │ └── repositories.kt │ │ └── resources │ │ ├── application-production.yml │ │ └── application.yml ├── spring-demo │ ├── Dockerfile │ ├── HELP.md │ ├── README.md │ ├── build.gradle.aot.kts │ ├── build.gradle.kts │ └── src │ │ ├── main │ │ ├── kotlin │ │ │ └── micro │ │ │ │ └── apps │ │ │ │ └── service │ │ │ │ ├── EntityApplication.kt │ │ │ │ ├── EntityController.kt │ │ │ │ ├── EntityRepository.kt │ │ │ │ ├── config │ │ │ │ ├── OpenAPIConfig.kt │ │ │ │ ├── OtelConfig.kt │ │ │ │ ├── SecurityConfig.kt │ │ │ │ ├── SwaggerConfig.kt │ │ │ │ ├── WebClientConfig.kt │ │ │ │ └── WebFluxConfig.kt │ │ │ │ ├── domain │ │ │ │ └── echo │ │ │ │ │ └── EchoService.kt │ │ │ │ └── extensions.kt │ │ └── resources │ │ │ ├── ValidationMessages.properties │ │ │ ├── application-production.yml │ │ │ ├── application.yml │ │ │ ├── banner.txt │ │ │ ├── data.sql │ │ │ ├── messages.properties │ │ │ └── schema.sql │ │ └── test │ │ └── kotlin │ │ └── micro │ │ └── apps │ │ └── service │ │ ├── EntityApplicationTest.kt │ │ ├── EntityControllerTests.kt │ │ └── ProjectConfig.kt ├── spring-graphql-jpa │ ├── .env.template │ ├── HELP.md │ ├── README.md │ ├── build.gradle.kts │ ├── items.http │ ├── message.http │ └── src │ │ ├── main │ │ ├── kotlin │ │ │ └── micro │ │ │ │ └── apps │ │ │ │ └── service │ │ │ │ ├── Application.kt │ │ │ │ ├── bootstrap │ │ │ │ └── DataInitializer.kt │ │ │ │ ├── config │ │ │ │ ├── Authorities.kt │ │ │ │ ├── SecurityConfig.kt │ │ │ │ └── UsersProperties.kt │ │ │ │ ├── domain │ │ │ │ ├── item │ │ │ │ │ └── Item.kt │ │ │ │ └── message │ │ │ │ │ └── Message.kt │ │ │ │ ├── exception │ │ │ │ ├── MessageConstants.kt │ │ │ │ └── exceptions.kt │ │ │ │ └── util │ │ │ │ └── Extensions.kt │ │ └── resources │ │ │ ├── application-local.yml │ │ │ ├── application-production.yml │ │ │ ├── application-test.yml │ │ │ ├── application.yml │ │ │ ├── db │ │ │ ├── migration │ │ │ │ └── V1__My_First_Migration.sql │ │ │ └── test-data │ │ │ │ └── .gitkeep │ │ │ ├── graphql │ │ │ ├── item.graphqls │ │ │ └── message.graphqls │ │ │ └── i18n │ │ │ ├── messages.properties │ │ │ └── messages_tr.properties │ │ └── test │ │ ├── kotlin │ │ └── micro │ │ │ └── apps │ │ │ └── service │ │ │ ├── DemoApplicationTests.kt │ │ │ └── domain │ │ │ └── item │ │ │ └── ItemControllerTest.kt │ │ └── resources │ │ ├── config │ │ └── application.yml │ │ └── graphql-test │ │ ├── MUTATION.AddItem.gql │ │ ├── QUERY.IntrospectionQuery.gql │ │ └── QUERY.ListItems.gql ├── spring-graphql-r2dbc │ ├── .env.template │ ├── HELP.md │ ├── README.md │ ├── books.http │ ├── build.gradle.kts │ ├── introspection.http │ ├── items.http │ ├── message.http │ └── src │ │ ├── main │ │ ├── kotlin │ │ │ └── micro │ │ │ │ └── apps │ │ │ │ └── service │ │ │ │ ├── Application.kt │ │ │ │ ├── bootstrap │ │ │ │ └── DataInitializer.kt │ │ │ │ ├── config │ │ │ │ ├── AppNativeHints.kt │ │ │ │ ├── Authorities.kt │ │ │ │ ├── DatabaseConfig.kt │ │ │ │ ├── SecurityConfig.kt │ │ │ │ ├── UsersProperties.kt │ │ │ │ └── WebClientConfig.kt │ │ │ │ ├── domain │ │ │ │ ├── book │ │ │ │ │ ├── AuthorRepository.kt │ │ │ │ │ ├── BookController.kt │ │ │ │ │ ├── BookRepository.kt │ │ │ │ │ ├── BookService.kt │ │ │ │ │ └── models.kt │ │ │ │ ├── item │ │ │ │ │ └── Item.kt │ │ │ │ └── message │ │ │ │ │ └── Message.kt │ │ │ │ ├── exception │ │ │ │ ├── MessageConstants.kt │ │ │ │ └── exceptions.kt │ │ │ │ └── util │ │ │ │ └── Extensions.kt │ │ └── resources │ │ │ ├── application-local.yml │ │ │ ├── application-production.yml │ │ │ ├── application-test.yml │ │ │ ├── application.yml │ │ │ ├── db │ │ │ └── migration │ │ │ │ ├── common │ │ │ │ └── V1_0_0__common_init.sql │ │ │ │ ├── h2 │ │ │ │ ├── V1_0_1__create_table_book.sql │ │ │ │ └── V1_1_0__create_table_item.sql │ │ │ │ ├── postgresql │ │ │ │ └── V1_0_1__create_table_book.sql │ │ │ │ └── sqlserver │ │ │ │ └── V1_0_1__create_table_book.sql │ │ │ ├── graphql │ │ │ ├── book.graphqls │ │ │ ├── item.graphqls │ │ │ └── message.graphqls │ │ │ └── i18n │ │ │ ├── messages.properties │ │ │ └── messages_tr.properties │ │ └── test │ │ ├── kotlin │ │ └── micro │ │ │ └── apps │ │ │ └── service │ │ │ ├── DemoApplicationTests.kt │ │ │ └── domain │ │ │ ├── book │ │ │ ├── BookControllerTest.kt │ │ │ └── BookIntegrationTest.kt │ │ │ └── item │ │ │ └── ItemControllerTest.kt │ │ └── resources │ │ ├── config │ │ └── application.yml │ │ ├── db │ │ └── testdata │ │ │ └── afterMigrate.sql │ │ └── graphql-test │ │ ├── MUTATION.AddItem.gql │ │ ├── MUTATION.CreateBook.gql │ │ ├── QUERY.IntrospectionQuery.gql │ │ └── QUERY.ListItems.gql ├── spring-graphql-redis │ ├── README.md │ ├── build.gradle.kts │ └── src │ │ ├── data │ │ └── employee.redis │ │ ├── main │ │ ├── kotlin │ │ │ └── micro │ │ │ │ └── apps │ │ │ │ └── service │ │ │ │ ├── Application.kt │ │ │ │ ├── bootstrap │ │ │ │ └── DataInitializer.kt │ │ │ │ ├── config │ │ │ │ ├── RedisConfig.kt │ │ │ │ └── properties.kt │ │ │ │ └── domain │ │ │ │ ├── account │ │ │ │ ├── AccountController.kt │ │ │ │ ├── AccountService.kt │ │ │ │ ├── extensions.kt │ │ │ │ ├── models.kt │ │ │ │ └── repositories.kt │ │ │ │ ├── person │ │ │ │ ├── PersonController.kt │ │ │ │ ├── mock-person.kt │ │ │ │ ├── people.kt │ │ │ │ └── repositories.kt │ │ │ │ ├── product │ │ │ │ └── .gitkeep │ │ │ │ └── user │ │ │ │ ├── UserController.kt │ │ │ │ ├── models.kt │ │ │ │ └── repositories.kt │ │ └── resources │ │ │ ├── application-local.yml │ │ │ ├── application-production.yml │ │ │ ├── application-test.yml │ │ │ └── application.yml │ │ └── test │ │ ├── kotlin │ │ └── micro │ │ │ └── apps │ │ │ └── service │ │ │ └── ApplicationTests.kt │ │ └── resources │ │ ├── config │ │ └── application.yml │ │ └── graphql-test │ │ ├── MUTATION.AddItem.gql │ │ ├── QUERY.IntrospectionQuery.gql │ │ └── QUERY.ListItems.gql ├── spring-kafka-functions │ ├── README.md │ ├── build.gradle.kts │ └── src │ │ ├── main │ │ ├── kotlin │ │ │ └── micro │ │ │ │ └── apps │ │ │ │ └── service │ │ │ │ └── StreamsApplication.kt │ │ └── resources │ │ │ ├── application-production.yml │ │ │ └── application.yml │ │ └── test │ │ └── kotlin │ │ └── micro │ │ └── apps │ │ └── service │ │ └── StreamsApplicationTest.kt ├── streams │ ├── README.md │ ├── build.gradle.kts │ └── src │ │ ├── main │ │ ├── kotlin │ │ │ └── micro │ │ │ │ └── apps │ │ │ │ └── service │ │ │ │ └── StreamsApplication.kt │ │ └── resources │ │ │ ├── aead_keyset.json │ │ │ ├── application-production.yml │ │ │ └── application.yml │ │ └── test │ │ └── kotlin │ │ └── micro │ │ └── apps │ │ └── service │ │ └── StreamsApplicationTest.kt ├── webapp │ └── build.gradle.kts.bak └── wordcount │ ├── README.md │ ├── build.gradle.kts │ └── src │ ├── main │ ├── kotlin │ │ └── micro │ │ │ └── apps │ │ │ └── service │ │ │ └── WordcountApplication.kt │ └── resources │ │ ├── application-production.yml │ │ └── application.yml │ └── test │ └── kotlin │ └── micro │ └── apps │ └── service │ └── WordcountApplicationTest.kt ├── settings.gradle.kts └── skaffold.yaml /.dive.yaml: -------------------------------------------------------------------------------- 1 | diff: 2 | # You can change the default files shown in the filetree (right pane). All diff types are shown by default. 3 | hide: 4 | - unmodified 5 | 6 | filetree: 7 | # Show the file attributes next to the filetree 8 | show-attributes: false 9 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | * 2 | !build/*-runner 3 | !build/*-runner.jar 4 | !build/lib/* -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 4 6 | end_of_line = lf 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | 11 | [*.md] 12 | max_line_length = off 13 | trim_trailing_whitespace = false 14 | 15 | [*.{yml, yaml}] 16 | indent_style = space 17 | indent_size = 2 18 | 19 | [gradlew.bat] 20 | end_of_line = crlf 21 | 22 | [{package, bower}.json] 23 | indent_style = space 24 | indent_size = 2 25 | 26 | [*.{kt, kts}] 27 | # possible values: number (e.g. 120) (package name, imports & comments are ignored), "off" 28 | # it's automatically set to 100 on `ktlint --android ...` (per Android Kotlin Style Guide) 29 | max_line_length = off 30 | disabled-rules=filename,import-ordering 31 | -------------------------------------------------------------------------------- /.env.template: -------------------------------------------------------------------------------- 1 | # `cp .env.example .env` and set real `secret` values in `.env` 2 | REDIS_CLOUD_HOST=redis-12345.secret.cloud.redislabs.com:12345 3 | REDIS_CLOUD_PASSWORD=secret 4 | 5 | # OpenTelemetry 6 | OTEL_RESOURCE_ATTRIBUTES=service.name=micro-apps 7 | OTEL_METRICS_EXPORTER=none 8 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # 2 | # https://help.github.com/articles/dealing-with-line-endings/ 3 | # 4 | # Set the default behavior, in case people don't have core.autocrlf set. 5 | * text=auto 6 | CONTRIBUTING.md export-ignore 7 | 8 | # Declare files that will always have CRLF line endings on checkout. 9 | *.bat text eol=crlf 10 | *.cmd text eol=crlf 11 | 12 | # Declare files that will always have LF line endings on checkout. 13 | *.sh text eol=lf 14 | -------------------------------------------------------------------------------- /.gitbook.yaml: -------------------------------------------------------------------------------- 1 | root: ./docs/ 2 | structure: 3 | readme: ../README.md 4 | summary: SUMMARY.md 5 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/about-codeowners/ 2 | # for more info about CODEOWNERS file 3 | 4 | # It uses the same pattern rule for gitignore file 5 | # https://git-scm.com/docs/gitignore#_pattern_format 6 | 7 | # Core 8 | **/build.gradle.kts @xmlking 9 | libs/kbeam @xmlking 10 | apps/demo @xmlking 11 | 12 | docs/* @xmlking 13 | deploy/* @xmlking 14 | *.kt xmlking+github@email.com 15 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [ xmlking ] 4 | open_collective: xmlking 5 | 6 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/docs.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Documentation request 3 | about: Suggest an improvement to the documentation 4 | title: '' 5 | labels: 'documentation' 6 | assignees: '' 7 | 8 | --- 9 | 10 | Please describe here what you would like to see documented. 11 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/question.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Question 3 | about: Questions on micro-apps usage 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Please consider asking your question on our [discussions](https://github.com/xmlking/micro-apps/discussions) 11 | The github issue tracker is for bugs and feature requests.** 12 | -------------------------------------------------------------------------------- /.github/chglog/config.yml: -------------------------------------------------------------------------------- 1 | style: github 2 | template: CHANGELOG.tpl.md 3 | info: 4 | title: CHANGELOG 5 | repository_url: https://github.com/xmlking/micro-apps 6 | options: 7 | commits: 8 | # filters: 9 | # Type: 10 | # - feat 11 | # - fix 12 | # - perf 13 | # - refactor 14 | commit_groups: 15 | # title_maps: 16 | # feat: Features 17 | # fix: Bug Fixes 18 | # perf: Performance Improvements 19 | # refactor: Code Refactoring 20 | header: 21 | pattern: "^(\\w*)(?:\\(([\\w\\$\\.\\-\\*\\s]*)\\))?\\:\\s(.*)$" 22 | pattern_maps: 23 | - Type 24 | - Scope 25 | - Subject 26 | notes: 27 | keywords: 28 | - BREAKING CHANGE 29 | -------------------------------------------------------------------------------- /.github/codeql/codeql-config.yml: -------------------------------------------------------------------------------- 1 | name: "CodeQL config" 2 | 3 | queries: 4 | - uses: security-and-quality 5 | # Run all extra query suites, both because we want to 6 | # and because it'll act as extra testing. This is why 7 | # we include both even though one is a superset of the 8 | # other, because we're testing the parsing logic and 9 | # that the suites exist in the codeql bundle. 10 | - uses: security-extended 11 | -------------------------------------------------------------------------------- /.github/codeql/custom-queries/java/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmlking/micro-apps/135c0f6b8ccfe17121a367bbfdd8024c77ea3c51/.github/codeql/custom-queries/java/.gitkeep -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: github-actions 4 | directory: / 5 | labels: 6 | - dependencies 7 | - actions 8 | - "Skip Changelog" 9 | schedule: 10 | day: sunday 11 | interval: weekly 12 | 13 | - package-ecosystem: docker 14 | directory: / 15 | labels: 16 | - dependencies 17 | - docker 18 | - "Skip Changelog" 19 | schedule: 20 | day: sunday 21 | interval: weekly 22 | 23 | - package-ecosystem: gradle 24 | directory: / 25 | labels: 26 | - dependencies 27 | - gradle 28 | - "Skip Changelog" 29 | schedule: 30 | day: sunday 31 | interval: weekly 32 | -------------------------------------------------------------------------------- /.github/release.yml: -------------------------------------------------------------------------------- 1 | changelog: 2 | exclude: 3 | labels: 4 | - ignore-for-release 5 | authors: 6 | - octocat 7 | categories: 8 | - title: Breaking Changes 🛠 9 | labels: 10 | - breaking 11 | - title: Exciting New Features 🎉 12 | labels: 13 | - feature 14 | - title: Fixes 🔧 15 | labels: 16 | - fix 17 | - title: Other Changes 18 | labels: 19 | - "*" 20 | -------------------------------------------------------------------------------- /.github/stale.yml: -------------------------------------------------------------------------------- 1 | # Number of days of inactivity before an issue becomes stale 2 | daysUntilStale: 60 3 | # Number of days of inactivity before a stale issue is closed 4 | daysUntilClose: 7 5 | # Issues with these labels will never be considered stale 6 | exemptLabels: 7 | - pinned 8 | - security 9 | # Label to use when marking an issue as stale 10 | staleLabel: wontfix 11 | # Comment to post when marking an issue as stale. Set to `false` to disable 12 | markComment: > 13 | This issue has been automatically marked as stale because it has not had 14 | recent activity. It will be closed if no further activity occurs. Thank you 15 | for your contributions. 16 | # Comment to post when closing a stale issue. Set to `false` to disable 17 | closeComment: false 18 | -------------------------------------------------------------------------------- /.github/todo_workflows/build-without-koverVerify.yml: -------------------------------------------------------------------------------- 1 | name: Java CI with Gradle 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | pull_request: 7 | branches: [ main ] 8 | 9 | jobs: 10 | build: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v3 14 | - name: Set up JDK 17 15 | uses: actions/setup-java@v3 16 | with: 17 | java-version: 17 18 | distribution: zulu 19 | cache: gradle 20 | - name: Grant execute permission for gradlew 21 | run: chmod +x gradlew 22 | - name: Build with Gradle 23 | run: ./gradlew build -x koverVerify # skipping koverVerify to not fail if the coverage has lowered 24 | - name: Upload coverage reports 25 | uses: codecov/codecov-action@v2 26 | with: 27 | files: build/reports/kover/report.xml 28 | -------------------------------------------------------------------------------- /.github/todo_workflows/kover-verify-pr.yml: -------------------------------------------------------------------------------- 1 | # https://lengrand.fr/kover-code-coverage-plugin-for-kotlin/ 2 | name: Checking coverage with Gradle 3 | 4 | on: 5 | push: 6 | branches: [ main ] 7 | pull_request: 8 | branches: [ main ] 9 | 10 | jobs: 11 | build: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v3 15 | - name: Set up JDK 17 16 | uses: actions/setup-java@v3 17 | with: 18 | java-version: 17 19 | distribution: zulu 20 | cache: gradle 21 | - name: Grant execute permission for gradlew 22 | run: chmod +x gradlew 23 | - name: Check coverage metrics 24 | run: ./gradlew koverVerify 25 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml.bak: -------------------------------------------------------------------------------- 1 | name: CodeQL Analysis 2 | permissions: 3 | actions: read 4 | contents: read 5 | pull-requests: read 6 | security-events: write 7 | on: 8 | push: 9 | branches: [ main ] 10 | pull_request: 11 | # The branches below must be a subset of the branches above 12 | branches: [ main ] 13 | schedule: 14 | # ┌───────────── minute (0 - 59) 15 | # │ ┌───────────── hour (0 - 23) 16 | # │ │ ┌───────────── day of the month (1 - 31) 17 | # │ │ │ ┌───────────── month (1 - 12 or JAN-DEC) 18 | # │ │ │ │ ┌───────────── day of the week (0 - 6 or SUN-SAT) 19 | # │ │ │ │ │ 20 | # │ │ │ │ │ 21 | # │ │ │ │ │ 22 | # * * * * * 23 | - cron: '30 1 * * *' 24 | 25 | jobs: 26 | call-codeQL-analysis: 27 | name: Static Code Analysis with CodeQL 28 | uses: actions/reusable-workflows/.github/workflows/codeql-analysis.yml@main 29 | -------------------------------------------------------------------------------- /.github/workflows/conventional-label.yml: -------------------------------------------------------------------------------- 1 | on: 2 | pull_request: 3 | types: [ opened, edited ] 4 | name: conventional-release-labels 5 | jobs: 6 | label: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - uses: bcoe/conventional-release-labels@v1 10 | -------------------------------------------------------------------------------- /.github/workflows/deploy.yml: -------------------------------------------------------------------------------- 1 | name: Deploy 2 | on: 3 | release: 4 | types: [ published ] 5 | 6 | env: 7 | CI: true 8 | 9 | jobs: 10 | deploy: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: Checkout Repository 14 | uses: actions/checkout@v3 15 | #jobs: 16 | # BINTRAY_UPLOAD: 17 | # name: Bintray Upload 18 | # runs-on: ubuntu-latest 19 | # env: 20 | # TRAVIS: true 21 | # BINTRAY_USER: ${{ secrets.BINTRAY_USER }} 22 | # BINTRAY_KEY: ${{ secrets.BINTRAY_KEY }} 23 | # steps: 24 | # - name: Checkout Repository 25 | # uses: actions/checkout@v3 26 | # - name: Set up JDK 21 27 | # uses: actions/setup-java@v3 28 | # with: 29 | # java-version: 21 30 | # distribution: zulu 31 | # - name: Perform bintray upload 32 | # run: ./gradlew bintrayUpload 33 | -------------------------------------------------------------------------------- /.github/workflows/docs.yml: -------------------------------------------------------------------------------- 1 | # https://github.com/kotest/kotest/tree/master/.github/workflows 2 | name: docs 3 | on: 4 | workflow_dispatch: 5 | push: 6 | branches: 7 | - main 8 | paths: 9 | - 'documentation/**' 10 | jobs: 11 | deploy: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - name: Checkout Repository 15 | uses: actions/checkout@v3 16 | - name: Set up Node 20 17 | - uses: actions/setup-node@v3 18 | with: 19 | node-version: '20.x' 20 | - name: Release to GitHub Pages 21 | env: 22 | USE_SSH: true 23 | GIT_USER: git 24 | run: | 25 | git config user.name github-actions 26 | git config user.email github-actions@github.com 27 | npm --prefix documentation ci 28 | npm --prefix documentation run build 29 | mv documentation/build docs 30 | echo "kashmora.com" > docs/CNAME 31 | echo "kashmora.com" > CNAME 32 | git add docs -f 33 | git commit -m "Updated docs" 34 | git push origin main:gh-pages --force 35 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Sumanth Chinthagunta 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Supported Versions 4 | 5 | Use this section to tell people about which versions of your project are currently being supported with security 6 | updates. 7 | 8 | | Version | Supported | 9 | | ------- | ------------------ | 10 | | 5.1.x | :white_check_mark: | 11 | | 5.0.x | :x: | 12 | | 4.0.x | :white_check_mark: | 13 | | < 4.0 | :x: | 14 | 15 | ## Reporting a Vulnerability 16 | 17 | Use this section to tell people how to report a vulnerability. 18 | 19 | Tell them where to go, how often they can expect to get an update on a reported vulnerability, what to expect if the 20 | vulnerability is accepted or declined, etc. 21 | -------------------------------------------------------------------------------- /TODO.md: -------------------------------------------------------------------------------- 1 | # TODO 2 | 3 | * Building Reactive Pipelines with Kotlin & Spring 4 | * https://github.com/mkheck/building-reactive-pipelines-with-kotlin 5 | * Aggregated Jacoco reports in a multi-project Gradle build 6 | * https://gist.github.com/aalmiray/e6f54aa4b3803be0bcac 7 | -------------------------------------------------------------------------------- /buf.work.yaml: -------------------------------------------------------------------------------- 1 | version: v1 2 | directories: 3 | - libs/proto/src/main/proto 4 | - libs/proto/src/main/third_party_proto 5 | -------------------------------------------------------------------------------- /buildSrc/settings.gradle.kts: -------------------------------------------------------------------------------- 1 | // rootProject.name = ("buildSrc") 2 | dependencyResolutionManagement { 3 | versionCatalogs { 4 | create("libs") { 5 | from(files("../gradle/libs.versions.toml")) 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /buildSrc/src/main/kotlin/micro.apps.build.internal.convention-base.gradle.kts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmlking/micro-apps/135c0f6b8ccfe17121a367bbfdd8024c77ea3c51/buildSrc/src/main/kotlin/micro.apps.build.internal.convention-base.gradle.kts -------------------------------------------------------------------------------- /buildSrc/src/main/kotlin/micro.apps.build.internal.convention-benchmark.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | // kotlin("jvm") 3 | // id("org.jetbrains.kotlin.plugin.allopen") 4 | // id("org.jetbrains.kotlinx.benchmark") 5 | } 6 | 7 | //allOpen { 8 | // annotation("org.openjdk.jmh.annotations.State") 9 | // annotation("org.openjdk.jmh.annotations.BenchmarkMode") 10 | //} 11 | -------------------------------------------------------------------------------- /buildSrc/src/main/kotlin/micro.apps.build.internal.convention-quality.gradle.kts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmlking/micro-apps/135c0f6b8ccfe17121a367bbfdd8024c77ea3c51/buildSrc/src/main/kotlin/micro.apps.build.internal.convention-quality.gradle.kts -------------------------------------------------------------------------------- /cog.toml: -------------------------------------------------------------------------------- 1 | pre_bump_hooks = [] 2 | post_bump_hooks = [] 3 | 4 | [commit_types] 5 | 6 | [changelog] 7 | path = "CHANGELOG.md" 8 | authors = [] 9 | 10 | [bump_profiles] 11 | -------------------------------------------------------------------------------- /config/base/beam/cronjob.yml: -------------------------------------------------------------------------------- 1 | apiVersion: batch/v1beta1 2 | kind: CronJob 3 | metadata: 4 | name: beam-schedule 5 | spec: 6 | schedule: "*/1 * * * *" 7 | # Do not start a new pipeline if the previous one has not completed 8 | concurrencyPolicy: Forbid 9 | jobTemplate: 10 | spec: 11 | template: 12 | spec: 13 | containers: 14 | - name: beam-pipeline 15 | image: xmlking/beam-scheduling-kubernetes 16 | imagePullPolicy: IfNotPresent 17 | restartPolicy: OnFailure 18 | -------------------------------------------------------------------------------- /config/base/elastic/README.md: -------------------------------------------------------------------------------- 1 | # Elasticsearch 2 | 3 | Elasticsearch is a distributed, RESTful search and analytics engine capable of solving a growing number of use cases. As 4 | the heart of the Elastic Stack, it centrally stores your data so you can discover the expected and uncover the 5 | unexpected. 6 | 7 | > This default distribution is governed by the Elastic License, and includes the [full set of free features](https://www.elastic.co/subscriptions). 8 | 9 | This will run Elasticsearch in a single node via `env` variable baked into the container, we can run the container 10 | service via `docker run` command or in Kubernetes `kubectl apply -k deployment/`. 11 | 12 | ## Installed Plugins list 13 | 14 | - repository-s3 15 | - discovery-ec2 16 | - mapper-size 17 | - mapper-murmur3 18 | - mapper-annotated-text 19 | - ingest-attachment 20 | - analysis-icu 21 | - analysis-phonetic 22 | -------------------------------------------------------------------------------- /config/base/elastic/kustomization.yml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | 4 | commonLabels: 5 | app.kubernetes.io/name: elastic 6 | app.kubernetes.io/instance: elastic-abcxzy 7 | app.kubernetes.io/component: infra 8 | 9 | namePrefix: elastic- 10 | 11 | resources: 12 | - statefulset.yml 13 | - service.yml 14 | 15 | configMapGenerator: 16 | - name: env-vars 17 | literals: 18 | - ELASTIC_LOG_LEVEL=info 19 | -------------------------------------------------------------------------------- /config/base/elastic/service.yml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: elasticsearch 5 | labels: 6 | name: elasticsearch 7 | app: elasticsearch 8 | spec: 9 | type: ClusterIP 10 | selector: 11 | app: elasticsearch 12 | ports: 13 | - port: 9200 14 | protocol: TCP 15 | targetPort: 9200 16 | name: elasticsearch 17 | - port: 9300 18 | protocol: TCP 19 | targetPort: 9300 20 | name: cluster 21 | -------------------------------------------------------------------------------- /config/base/envoy/config/bootstrap.yaml: -------------------------------------------------------------------------------- 1 | node: 2 | id: id 3 | cluster: cluster 4 | 5 | admin: 6 | access_log_path: /dev/null 7 | address: 8 | socket_address: { address: 0.0.0.0, port_value: 9901 } 9 | 10 | dynamic_resources: 11 | lds_config: 12 | path: '/etc/envoy/listeners.yaml' 13 | cds_config: 14 | path: '/etc/envoy/clusters.yaml' 15 | 16 | layered_runtime: 17 | layers: 18 | - name: static_layer_0 19 | static_layer: 20 | overload: 21 | global_downstream_max_connections: 50000 22 | -------------------------------------------------------------------------------- /config/base/envoy/config/client_validation_context.yaml: -------------------------------------------------------------------------------- 1 | resources: 2 | - "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret 3 | name: client_validation_context 4 | validation_context: 5 | trusted_ca: 6 | filename: '/etc/certs/ca-cert.pem' 7 | -------------------------------------------------------------------------------- /config/base/envoy/config/endpoints.yaml: -------------------------------------------------------------------------------- 1 | version_info: '0' 2 | resources: 3 | - "@type": type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment 4 | cluster_name: echo_service2 5 | endpoints: 6 | - lb_endpoints: 7 | - endpoint: 8 | address: 9 | socket_address: { address: 192.168.2.244, port_value: 5001 } 10 | -------------------------------------------------------------------------------- /config/base/envoy/config/proxy_cert.yaml: -------------------------------------------------------------------------------- 1 | resources: 2 | - "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret 3 | name: proxy_cert 4 | tls_certificate: 5 | certificate_chain: 6 | filename: '/etc/certs/proxy-cert.pem' 7 | private_key: 8 | filename: '/etc/certs/proxy-key.pem' 9 | -------------------------------------------------------------------------------- /config/base/envoy/config/routes.yaml: -------------------------------------------------------------------------------- 1 | version_info: '0' 2 | resources: 3 | - "@type": type.googleapis.com/envoy.config.route.v3.RouteConfiguration 4 | name: route_config_0 5 | virtual_hosts: 6 | - name: local_service 7 | domains: [ '*' ] # "example.com" in prod 8 | routes: 9 | - match: { prefix: '/micro.apps.proto.account.v1.AccountService' } 10 | route: { cluster: account_service, max_stream_duration: { grpc_timeout_header_max: 15.0s } } 11 | - match: { prefix: '/micro.apps.proto.echo.v1.EchoService' } 12 | route: { cluster: echo_service, max_stream_duration: { grpc_timeout_header_max: 15.0s } } 13 | cors: 14 | allow_origin_string_match: 15 | - safe_regex: { google_re2: { }, regex: '\*' } 16 | allow_methods: GET, PUT, DELETE, POST, OPTIONS 17 | allow_headers: keep-alive,user-agent,cache-control,content-type,content-transfer-encoding,x-accept-content-transfer-encoding,x-accept-response-streaming,x-user-agent,x-grpc-web,grpc-timeout 18 | max_age: '1728000' 19 | -------------------------------------------------------------------------------- /config/base/envoy/config/upstream_validation_context.yaml: -------------------------------------------------------------------------------- 1 | resources: 2 | - "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.Secret 3 | name: upstream_validation_context 4 | validation_context: 5 | trusted_ca: 6 | filename: '/etc/certs/upstream-ca-cert.pem' 7 | match_subject_alt_names: { exact: 'localhost' } # for prod, e.g., www.sumo.com 8 | -------------------------------------------------------------------------------- /config/base/envoy/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | 4 | commonLabels: 5 | app.kubernetes.io/name: envoy 6 | app.kubernetes.io/instance: envoy-abcxzy 7 | app.kubernetes.io/component: infra 8 | app.kubernetes.io/part-of: yeti 9 | app.kubernetes.io/managed-by: kustomize 10 | commonAnnotations: 11 | org: acmeCorporation 12 | 13 | resources: 14 | - deployment.yaml 15 | - service.yaml 16 | 17 | configMapGenerator: 18 | - name: env-vars 19 | literals: 20 | - ENVOY_LOG_LEVEL=info 21 | - name: config 22 | files: 23 | - 'config/envoy.yaml' 24 | - 'config/clusters.yaml' 25 | - 'config/endpoints.yaml' 26 | - 'config/listeners.yaml' 27 | - 'config/routes.yaml' 28 | 29 | vars: 30 | - name: ENVOY_SERVICE_ENDPOINT 31 | objref: 32 | kind: Service 33 | name: envoy 34 | apiVersion: v1 35 | fieldref: 36 | fieldpath: metadata.name 37 | -------------------------------------------------------------------------------- /config/base/envoy/service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: envoy 5 | annotations: 6 | service.beta.kubernetes.io/do-loadbalancer-protocol: "tcp" 7 | service.beta.kubernetes.io/do-loadbalancer-enable-proxy-protocol: "true" 8 | spec: 9 | type: LoadBalancer 10 | # We want the servers to become available even if they're not ready 11 | publishNotReadyAddresses: true 12 | ports: 13 | - name: grpc-web 14 | port: 9090 15 | targetPort: http 16 | - name: grpc-web-secure 17 | port: 9443 18 | targetPort: https 19 | - name: http-admin 20 | port: 9901 21 | targetPort: admin 22 | -------------------------------------------------------------------------------- /config/base/kconfig.yaml: -------------------------------------------------------------------------------- 1 | varReference: 2 | - path: data 3 | kind: ConfigMap 4 | -------------------------------------------------------------------------------- /config/base/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | 4 | commonLabels: 5 | app.kubernetes.io/part-of: micro-apps 6 | app.kubernetes.io/managed-by: kustomize 7 | commonAnnotations: 8 | org: acmeCorporation 9 | 10 | resources: 11 | - service 12 | - elastic 13 | - nifi 14 | - postgres 15 | 16 | configurations: 17 | - kconfig.yaml 18 | 19 | secretGenerator: 20 | - name: secrets 21 | literals: 22 | - DATABASE_PASSWORD=fake 23 | -------------------------------------------------------------------------------- /config/base/nifi/README.md: -------------------------------------------------------------------------------- 1 | # Kubernetes NiFi Cluster 2 | 3 | [Apache NiFi](https://nifi.apache.org/) supports powerful and scalable directed graphs of data routing, transformation, 4 | and system mediation logic. 5 | 6 | My goal is to show how to run Apache NiFi Cluster in Kubernetes 7 | 8 | ## Prerequisites 9 | 10 | - Kubernetes Cluster 11 | - Ingress Controller 12 | 13 | ## Deployments 14 | 15 | This will deploy Apache NiFi in a Cluster mode with extenal Apache Zookeeper managing ellections: 16 | 17 | ```shell 18 | kubectl apply -k config/base/nifi 19 | ``` 20 | 21 | This will create: 22 | 23 | - 1x NiFi Namespace (all the items will be deployed here) 24 | - 3x Apache NiFi (each with it's own Service endpoint) 25 | - 1x Apache Zookeeper (accessible within the cluster only) 26 | - 1x Secrets (basic auth username/password: `admin:admin`) 27 | - 1x Ingress (access endpoint) 28 | 29 | > Important: If this is exposed to public remember to update the default `username/password`. 30 | 31 | ## Services 32 | 33 | ```shell 34 | kubectl get all,ing --namespace nifi 35 | ``` 36 | 37 | ## Reference 38 | 39 | - https://github.com/AlexsJones/nifi 40 | -------------------------------------------------------------------------------- /config/base/nifi/ingress.yml: -------------------------------------------------------------------------------- 1 | apiVersion: networking.k8s.io/v1beta1 2 | kind: Ingress 3 | metadata: 4 | name: nifi 5 | labels: 6 | app: nifi 7 | annotations: 8 | nginx.ingress.kubernetes.io/auth-type: basic 9 | nginx.ingress.kubernetes.io/auth-secret: nifi-basic-auth 10 | nginx.ingress.kubernetes.io/auth-realm: "Authentication Required" 11 | nginx.ingress.kubernetes.io/configuration-snippet: | 12 | server_tokens off; 13 | spec: 14 | rules: 15 | - host: nifi.kashmora.com 16 | http: 17 | paths: 18 | - path: / 19 | backend: 20 | serviceName: nifi 21 | servicePort: 8080 22 | -------------------------------------------------------------------------------- /config/base/nifi/kustomization.yml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | 4 | commonLabels: 5 | app.kubernetes.io/name: nifi 6 | app.kubernetes.io/instance: nifi-abcxzy 7 | app.kubernetes.io/component: infra 8 | 9 | namePrefix: nifi- 10 | 11 | resources: 12 | - statefulset.yml 13 | - secret.yml 14 | - service.yml 15 | - ingress.yml 16 | 17 | configMapGenerator: 18 | - name: env-vars 19 | literals: 20 | - NIFI_LOG_LEVEL=info 21 | -------------------------------------------------------------------------------- /config/base/nifi/secret.yml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Secret 4 | type: Opaque 5 | metadata: 6 | name: nifi-basic-auth 7 | labels: 8 | app: nifi 9 | data: 10 | auth: YWRtaW46JGFwcjEkSDY1dnBkTU8kMXAxOGMxN3BuZVFUT2ZjVC9TZkZzMQo= 11 | -------------------------------------------------------------------------------- /config/base/nifi/service.yml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Service 4 | metadata: 5 | name: nifi 6 | labels: 7 | app: nifi 8 | spec: 9 | type: NodePort 10 | selector: 11 | app: nifi 12 | ports: 13 | - protocol: TCP 14 | port: 8080 15 | targetPort: 8080 16 | name: nifi 17 | - protocol: TCP 18 | port: 8082 19 | targetPort: 8082 20 | name: cluster 21 | --- 22 | apiVersion: v1 23 | kind: Service 24 | metadata: 25 | name: zookeeper 26 | labels: 27 | app: zookeeper 28 | spec: 29 | type: ClusterIP 30 | selector: 31 | app: zookeeper 32 | "statefulset.kubernetes.io/pod-name": zookeeper-0 33 | ports: 34 | - protocol: TCP 35 | port: 2181 36 | targetPort: 2181 37 | name: zk 38 | - protocol: TCP 39 | port: 5111 40 | targetPort: 5111 41 | name: cmd 42 | -------------------------------------------------------------------------------- /config/base/postgres/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | 4 | commonLabels: 5 | app.kubernetes.io/name: postgres 6 | app.kubernetes.io/instance: postgres-abcxzy 7 | app.kubernetes.io/component: database 8 | 9 | resources: 10 | - statefulset.yaml 11 | - service.yaml 12 | - service-headless.yaml 13 | 14 | vars: 15 | - name: DATABASE_ENDPOINT 16 | objref: 17 | kind: Service 18 | name: postgres 19 | apiVersion: v1 20 | fieldref: 21 | fieldpath: metadata.name 22 | -------------------------------------------------------------------------------- /config/base/postgres/scripts/create_databases.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | set -u 5 | 6 | function create_user_and_database() { 7 | local database=$1 8 | local username=$2 9 | local password=$3 10 | echo " Creating user '$username' and database '$database'" 11 | psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" <<-EOSQL 12 | CREATE ROLE $username WITH PASSWORD '$password' NOSUPERUSER LOGIN; 13 | CREATE DATABASE $database; 14 | GRANT ALL PRIVILEGES ON DATABASE $database TO $username; 15 | EOSQL 16 | } 17 | 18 | if [ -n "$KEYCLOAK_DB" ]; then 19 | create_user_and_database $KEYCLOAK_DB $KEYCLOAK_DB_USER $KEYCLOAK_DB_PASSWORD 20 | fi 21 | 22 | -------------------------------------------------------------------------------- /config/base/postgres/scripts/create_extensions.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | set -u 5 | 6 | function create_extension() { 7 | local database=$1 8 | echo " Creating uuid-ossp extension" 9 | psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" <<-EOSQL 10 | CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; 11 | EOSQL 12 | } 13 | 14 | if [ -n "$POSTGRES_DB" ]; then 15 | create_extension $POSTGRES_DB 16 | fi 17 | -------------------------------------------------------------------------------- /config/base/postgres/service-headless.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Service 4 | metadata: 5 | name: postgres-headless 6 | labels: 7 | app: postgres 8 | spec: 9 | type: ClusterIP 10 | clusterIP: None 11 | ports: 12 | - name: tcp-pg 13 | port: 5432 14 | targetPort: tcp-pg 15 | selector: 16 | app: postgres 17 | -------------------------------------------------------------------------------- /config/base/postgres/service.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Service 4 | metadata: 5 | name: postgres 6 | labels: 7 | app: postgres 8 | spec: 9 | type: NodePort 10 | ports: 11 | - name: tcp-pg 12 | port: 5432 13 | targetPort: tcp-pg 14 | nodePort: 31432 15 | selector: 16 | app: postgres 17 | role: master 18 | -------------------------------------------------------------------------------- /config/base/service/greeting/deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: service 5 | spec: 6 | template: 7 | spec: 8 | containers: 9 | - name: service 10 | image: xmlking/greeting-service:latest 11 | imagePullPolicy: Always 12 | ports: 13 | - name: http 14 | containerPort: 8080 15 | protocol: TCP 16 | envFrom: 17 | - configMapRef: 18 | name: env-vars 19 | - configMapRef: 20 | name: env-vars-common 21 | - secretRef: 22 | name: secrets 23 | -------------------------------------------------------------------------------- /config/base/service/greeting/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | 4 | commonLabels: 5 | app.kubernetes.io/name: greeting-service 6 | app.kubernetes.io/instance: greeting-service-abcxzy 7 | app.kubernetes.io/component: microservice 8 | 9 | namePrefix: greeting- 10 | 11 | resources: 12 | - deployment.yaml 13 | - service.yaml 14 | 15 | configMapGenerator: 16 | - name: env-vars 17 | literals: 18 | - MICRO_SERVER_NAME=micro.service.greeting 19 | # - MICRO_SERVER_ADVERTISE="$(GREETING_SERVICE_ENDPOINT):8080" 20 | - DATABASE_HOST=$(DATABASE_ENDPOINT) 21 | 22 | vars: 23 | - name: GREETING_SERVICE_ENDPOINT 24 | objref: 25 | kind: Service 26 | name: service 27 | apiVersion: v1 28 | fieldref: 29 | fieldpath: metadata.name 30 | -------------------------------------------------------------------------------- /config/base/service/greeting/service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: service 5 | spec: 6 | type: ClusterIP 7 | # We want the servers to become available even if they're not ready 8 | publishNotReadyAddresses: true 9 | ports: 10 | - name: http 11 | port: 8080 12 | targetPort: http 13 | -------------------------------------------------------------------------------- /config/base/service/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | 4 | resources: 5 | - greeting 6 | 7 | configMapGenerator: 8 | # - name: env-vars 9 | # behavior: merge 10 | - name: env-vars-common 11 | literals: 12 | - APP_ENV=development 13 | - MICRO_LOG_LEVEL=debug 14 | 15 | #secretGenerator: 16 | # - name: app-tls 17 | # files: 18 | # - secret/tls.cert 19 | # - secret/tls.key 20 | -------------------------------------------------------------------------------- /config/base/service/spring/deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: service 5 | spec: 6 | template: 7 | metadata: 8 | annotations: 9 | prometheus.io/scrape: "true" 10 | #prometheus.io/port: "3101" 11 | prometheus.io/path: "/actuator/prometheus" 12 | spec: 13 | containers: 14 | - name: service 15 | image: xmlking/spring-service:latest 16 | imagePullPolicy: Always 17 | ports: 18 | - name: http 19 | containerPort: 8080 20 | protocol: TCP 21 | envFrom: 22 | - configMapRef: 23 | name: env-vars 24 | - configMapRef: 25 | name: env-vars-common 26 | - secretRef: 27 | name: secrets 28 | -------------------------------------------------------------------------------- /config/base/service/spring/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | 4 | commonLabels: 5 | app.kubernetes.io/name: spring-service 6 | app.kubernetes.io/instance: spring-service-abcxzy 7 | app.kubernetes.io/component: microservice 8 | 9 | namePrefix: spring- 10 | 11 | resources: 12 | - deployment.yaml 13 | - service.yaml 14 | 15 | configMapGenerator: 16 | - name: env-vars 17 | literals: 18 | - MICRO_SERVER_NAME=micro.service.spring 19 | # - MICRO_SERVER_ADVERTISE="$(GREETING_SERVICE_ENDPOINT):8080" 20 | - DATABASE_HOST=$(DATABASE_ENDPOINT) 21 | 22 | vars: 23 | - name: GREETING_SERVICE_ENDPOINT 24 | objref: 25 | kind: Service 26 | name: service 27 | apiVersion: v1 28 | fieldref: 29 | fieldpath: metadata.name 30 | -------------------------------------------------------------------------------- /config/base/service/spring/service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: service 5 | spec: 6 | type: ClusterIP 7 | # We want the servers to become available even if they're not ready 8 | publishNotReadyAddresses: true 9 | ports: 10 | - name: http 11 | port: 8080 12 | targetPort: http 13 | -------------------------------------------------------------------------------- /config/certs/.gitignore: -------------------------------------------------------------------------------- 1 | # *.pem 2 | *.h 3 | -------------------------------------------------------------------------------- /config/certs/ca-cert.cfg: -------------------------------------------------------------------------------- 1 | [req] 2 | distinguished_name = req_distinguished_name 3 | req_extensions = v3_req 4 | 5 | [req_distinguished_name] 6 | countryName = US 7 | countryName_default = US 8 | stateOrProvinceName = California 9 | stateOrProvinceName_default = California 10 | localityName = San Francisco 11 | localityName_default = San Francisco 12 | organizationName = Lyft 13 | organizationName_default = Lyft 14 | organizationalUnitName = Lyft Engineering 15 | organizationalUnitName_default = Lyft Engineering 16 | commonName = Test CA 17 | commonName_default = Test CA 18 | commonName_max = 64 19 | 20 | [v3_req] 21 | basicConstraints = CA:TRUE 22 | keyUsage = critical, cRLSign, keyCertSign 23 | subjectKeyIdentifier = hash 24 | 25 | [v3_ca] 26 | basicConstraints = critical, CA:TRUE 27 | keyUsage = critical, cRLSign, keyCertSign 28 | subjectKeyIdentifier = hash 29 | authorityKeyIdentifier = keyid:always 30 | -------------------------------------------------------------------------------- /config/certs/client-ecdsa-key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN EC PARAMETERS----- 2 | BggqhkjOPQMBBw== 3 | -----END EC PARAMETERS----- 4 | -----BEGIN EC PRIVATE KEY----- 5 | MHcCAQEEIBmplOmr4cATc0d4d3f1zCPnxv7VW7FNoqPTL15TsKTSoAoGCCqGSM49 6 | AwEHoUQDQgAE/98esleScyrse9Ac+ItzxUv+GThLEih31K+1M8d0t8c0bZ6V9zOw 7 | CdfgbYMs9Ft+/uMh8VfdTCedZOm9ATxOyw== 8 | -----END EC PRIVATE KEY----- 9 | -------------------------------------------------------------------------------- /config/certs/proxy-ecdsa-key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN EC PARAMETERS----- 2 | BggqhkjOPQMBBw== 3 | -----END EC PARAMETERS----- 4 | -----BEGIN EC PRIVATE KEY----- 5 | MHcCAQEEIEQurvyPoQYJMCXexSbi9sUfgtCoa0Uu/Q3N/Y+rSKadoAoGCCqGSM49 6 | AwEHoUQDQgAED1ODFu+z3jbgHXexWUxzU2qByaaHsPPOFrXPFNj1VQkL/DftMrIZ 7 | 0PldO6/qoqKYFVh5kRKZSmNx2NWaCzRYOQ== 8 | -----END EC PRIVATE KEY----- 9 | -------------------------------------------------------------------------------- /config/certs/upstream-ca-cert.cfg: -------------------------------------------------------------------------------- 1 | [req] 2 | distinguished_name = req_distinguished_name 3 | req_extensions = v3_req 4 | 5 | [req_distinguished_name] 6 | countryName = US 7 | countryName_default = US 8 | stateOrProvinceName = California 9 | stateOrProvinceName_default = California 10 | localityName = San Francisco 11 | localityName_default = San Francisco 12 | organizationName = Lyft 13 | organizationName_default = Lyft 14 | organizationalUnitName = Lyft Engineering 15 | organizationalUnitName_default = Lyft Engineering 16 | commonName = Test Upstream CA 17 | commonName_default = Test Upstream CA 18 | commonName_max = 64 19 | 20 | [v3_req] 21 | basicConstraints = CA:TRUE 22 | keyUsage = critical, cRLSign, keyCertSign 23 | subjectKeyIdentifier = hash 24 | 25 | [v3_ca] 26 | basicConstraints = critical, CA:TRUE 27 | keyUsage = critical, cRLSign, keyCertSign 28 | subjectKeyIdentifier = hash 29 | authorityKeyIdentifier = keyid:always 30 | -------------------------------------------------------------------------------- /config/envs/development/patches/image-pull-policy-if-not-present.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: service 5 | spec: 6 | template: 7 | spec: 8 | containers: 9 | - name: service 10 | imagePullPolicy: IfNotPresent 11 | -------------------------------------------------------------------------------- /config/envs/production/patches/image-pull-policy-if-not-present.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: service 5 | spec: 6 | template: 7 | spec: 8 | containers: 9 | - name: service 10 | imagePullPolicy: IfNotPresent 11 | -------------------------------------------------------------------------------- /config/envs/production/patches/resource_limit.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: apps/v1 3 | kind: Deployment 4 | metadata: 5 | name: service 6 | spec: 7 | template: 8 | spec: 9 | containers: 10 | - name: service 11 | resources: 12 | requests: 13 | cpu: 250m 14 | memory: 1G 15 | limits: 16 | cpu: 500m 17 | memory: 2G 18 | -------------------------------------------------------------------------------- /config/envs/production/resources/hpa.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: autoscaling/v2beta2 2 | kind: HorizontalPodAutoscaler 3 | metadata: 4 | name: account-service-hpa 5 | spec: 6 | minReplicas: 1 7 | maxReplicas: 5 8 | metrics: 9 | - resource: 10 | name: cpu 11 | target: 12 | averageUtilization: 70 13 | type: Utilization 14 | type: Resource 15 | - resource: 16 | name: memory 17 | target: 18 | averageUtilization: 70 19 | type: Utilization 20 | type: Resource 21 | scaleTargetRef: 22 | apiVersion: apps/v1 23 | kind: Deployment 24 | name: account-service 25 | -------------------------------------------------------------------------------- /config/envs/staging/patches/image-pull-policy-if-not-present.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: service 5 | spec: 6 | template: 7 | spec: 8 | containers: 9 | - name: service 10 | imagePullPolicy: IfNotPresent 11 | -------------------------------------------------------------------------------- /delivery/envs/development.yaml: -------------------------------------------------------------------------------- 1 | cluster_name: sumo 2 | project: micro-apps 3 | compute: # choose "region" or "zone" 4 | zone: us-west2-a 5 | namespace: development 6 | no_pr_approval_required: true 7 | -------------------------------------------------------------------------------- /delivery/envs/production.yaml: -------------------------------------------------------------------------------- 1 | cluster_name: sumo 2 | project: micro-apps 3 | compute: # choose "region" or "zone" 4 | zone: us-west2-a 5 | namespace: production 6 | no_pr_approval_required: false 7 | -------------------------------------------------------------------------------- /delivery/envs/staging.yaml: -------------------------------------------------------------------------------- 1 | cluster_name: sumo 2 | project: micro-apps 3 | compute: # choose "region" or "zone" 4 | zone: us-west2-a 5 | namespace: staging 6 | no_pr_approval_required: true 7 | -------------------------------------------------------------------------------- /docs/SUMMARY.md: -------------------------------------------------------------------------------- 1 | # Table of Contents 2 | 3 | - [Introduction](../README.md) 4 | - Getting Started 5 | - [Why](introduction/why.md) 6 | - [Hot it Works](introduction/gitflow.md) 7 | - [Installation](introduction/installation.md) 8 | - [Usage](introduction/gitflow-usage.md) 9 | - [Project Layout](introduction/project-layout.md) 10 | - Concepts 11 | - [Introduction](concepts/intro.md) 12 | - [Release](concepts/release.md) 13 | - [Versioning](concepts/versioning.md) 14 | - [Monorepos](concepts/monorepo.md) 15 | - Advanced 16 | - [GitOps](advanced/gitops.md) 17 | - [Gradle](advanced/gradle.md) 18 | - [Makefile](advanced/makefile.md) 19 | - [Jenkins](advanced/jenkins.md) 20 | - [Github Actions](advanced/github-actions.md) 21 | - Dev Ops 22 | - [Keycloak](devops/keycloak.md) 23 | - Recipes 24 | - [Steaming Pipeline](recipes/streaming.md) 25 | - [Recipe 2](recipes/recipe2.md) 26 | - [Change Log](../CHANGELOG.md) 27 | - [FAQ](faq/faq.md) 28 | 29 | 30 | -------------------------------------------------------------------------------- /docs/advanced/database.md: -------------------------------------------------------------------------------- 1 | # Database 2 | 3 | 4 | 5 | ## H2 6 | Starting the server doesn't open a database. Databases are opened as soon as a client connects. 7 | 8 | ### Dialect and Drivers 9 | H2 server has its own jdbc driver. It will not work with others. 10 | 11 | But H2 server is compatible with different dialects. But the database connection should initialize with spesific mode. example jdbc url compatible with MSSQLServer: 12 | 13 | ``` 14 | jdbc:h2:~/test;MODE=MSSQLServer 15 | ``` 16 | 17 | or it can be change anytime using simple sql: 18 | 19 | ```sql 20 | SET MODE MSSQLServer 21 | ``` 22 | 23 | H2 itself has its own SQL dialect. It is enabled as default. 24 | 25 | 26 | ## Flyway 27 | 28 | - Using the basic `schema.sql` and `data.sql` scripts (a.k.a `spring.sql.init.mode`) alongside **Flyway** or **Liquibase** is not recommended and support will be removed in a future release. 29 | -------------------------------------------------------------------------------- /docs/advanced/dependencies.md: -------------------------------------------------------------------------------- 1 | # dependencies 2 | 3 | ## Gradle dependencies 4 | 5 | ### Spring Boot basic 6 | 7 | ```gradle 8 | implementation(libs.bundles.spring.basic) 9 | ``` 10 | 11 | ### Spring Boot + gRPC 12 | 13 | ```gradle 14 | implementation(libs.bundles.spring.basic) 15 | 16 | implementation(projects.libs.proto) 17 | implementation(libs.bundles.spring.grpc) 18 | ``` 19 | 20 | if you are using `org.springframework.experimental.aot` plugin 21 | 22 | ```gradle 23 | implementation(projects.libs.proto) 24 | implementation(libs.bundles.spring.grpc) { 25 | exclude( group = "io.netty", module ="netty-tcnative-boringssl-static") 26 | exclude( group = "io.grpc", module ="grpc-netty-shaded") 27 | } 28 | implementation(libs.grpc.netty) 29 | ``` 30 | -------------------------------------------------------------------------------- /docs/advanced/dgraph.md: -------------------------------------------------------------------------------- 1 | # dGraph 2 | 3 | ## Start 4 | 5 | ```bash 6 | # start zero1, alpha1 and ratel 7 | docker compose -f infra/dgraph.yml up 8 | # check 9 | docker compose -f infra/dgraph.yml ps 10 | # stop all 11 | docker compose -f infra/dgraph.yml down 12 | ``` 13 | -------------------------------------------------------------------------------- /docs/advanced/gcs.md: -------------------------------------------------------------------------------- 1 | # GCS 2 | 3 | # list keystore files in GCS bucket 4 | 5 | ``` 6 | export GOOGLE_APPLICATION_CREDENTIALS=/Users/sumo/my-gcs.json 7 | gcloud auth activate-service-account --key-file $GOOGLE_APPLICATION_CREDENTIALS 8 | gsutil ls gs://my-project-bucket-name/files 9 | ``` 10 | -------------------------------------------------------------------------------- /docs/advanced/github-actions.md: -------------------------------------------------------------------------------- 1 | # GitHub Actions 2 | 3 | - build executable in native mode 4 | - put the executable in a Docker image 5 | - publish the docker image to a remote registry 6 | - deploy it on GCP with Cloud Run 7 | 8 | See [github actions](../../.github/main.yml) 9 | 10 | ## GitHub Workflows 11 | 12 | - Push Pipeline 13 | - Pull Request(PR) Pipeline 14 | - Release Pipeline 15 | - Deployment Pipeline 16 | 17 | ### Feature Branch Push Pipeline 18 | 19 | - lint 20 | - unit tests 21 | 22 | ### PR Pipeline 23 | 24 | > triggered when PR is created for `main` branch 25 | 26 | - lint 27 | - unit tests 28 | - integration tests 29 | 30 | ### Release Pipeline 31 | 32 | - build docker images 33 | - sign images 34 | - push images to GCR 35 | - generate build/kubernetes.yaml for k8s with Helm or Kustomize 36 | - generate release on GitHub 37 | 38 | ### Deployment Pipeline 39 | 40 | - Deploy to KinD on CI 41 | - E2E Test 42 | 43 | - deploy to GKE 44 | 45 | ## Reference 46 | 47 | - https://medium.com/@max.day/how-to-use-github-actions-to-deploy-your-quarkus-app-to-gcp-6ed5d9fdecb3 48 | - https://github.com/maxday/quarkus-demo-actions 49 | -------------------------------------------------------------------------------- /docs/advanced/jenkins.md: -------------------------------------------------------------------------------- 1 | # jenkins 2 | 3 | [Multi-branch Jenkins Pipeline](https://jenkins.io/doc/tutorials/build-a-multibranch-pipeline-project/) 4 | 5 | ##### Feature Branch Pipeline 6 | 7 | ![pipeline-feature](../images/pipeline-feature.png) 8 | 9 | ##### Develop Branch Pipeline 10 | 11 | ![pipeline-develop](../images/pipeline-develop.png) 12 | 13 | ##### Master Branch Pipeline 14 | 15 | ![pipeline-master](../images/pipeline-master.png) 16 | 17 | ### Reference 18 | 19 | - [nx-jenkins-build](https://github.com/nrwl/nx-jenkins-build) 20 | -------------------------------------------------------------------------------- /docs/advanced/kubernetes.md: -------------------------------------------------------------------------------- 1 | # Kubernetes for Dev 2 | 3 | How to set up a serious Kubernetes terminal 4 | 5 | ## tools 6 | 7 | ### CLI tools 8 | 9 | - kubectx 10 | - kubens 11 | - k9s 12 | 13 | #### Using CLI tools 14 | 15 | ```bash 16 | kubectx my-context 17 | kubens kube-system 18 | k9s 19 | ``` 20 | 21 | ## Verification 22 | 23 | ### Check tools 24 | 25 | - popeye 26 | - kubeval 27 | 28 | ## Reference 29 | 30 | - [Compendium of Kubernetes Application Deployment Tools](https://medium.com/@KarlKFI/compendium-of-kubernetes-application-deployment-tools-80a828c91e8f) 31 | -------------------------------------------------------------------------------- /docs/advanced/makefile.md: -------------------------------------------------------------------------------- 1 | # Makefile -------------------------------------------------------------------------------- /docs/advanced/spring.md: -------------------------------------------------------------------------------- 1 | # Spring 2 | 3 | ## Spring Cloud 4 | 5 | ## Spring Cloud Functions 6 | 7 | Ref: https://github.com/LeapAheadWithRedis6-2/redis-whats-new-functions 8 | 9 | ```gradle 10 | implementation(enforcedPlatform(libs.spring.cloud.gcp.bom.get().toString())) 11 | implementation(libs.bundles.spring.cloud.functions) 12 | ``` 13 | 14 | ## Spring Cloud GCP 15 | 16 | ```gradle 17 | implementation(enforcedPlatform(libs.spring.cloud.gcp.bom.get().toString())) 18 | runtimeOnly(libs.bundles.spring.cloud.gcp.basic) 19 | ``` 20 | -------------------------------------------------------------------------------- /docs/awesome/awesome-gradle.md: -------------------------------------------------------------------------------- 1 | Awesome Gradle 2 | 3 | A curated list of awesome Gradle build tool tips and blogs. 4 | -------------------------------------------------------------------------------- /docs/awesome/awesome-spring.md: -------------------------------------------------------------------------------- 1 | Awesome Spring 2 | 3 | A curated list of awesome Spring Framework libraries and blogs. 4 | 5 | ## Architecture 6 | - [Hexagonal Architecture on Spring Boot](https://jivimberg.io/blog/2020/02/01/hexagonal-architecture-on-spring-boot/) 7 | - [Using UUID on Spring Data JPA Entities](https://jivimberg.io/blog/2018/11/05/using-uuid-on-spring-data-jpa-entities/) 8 | 9 | ### Event Driven Architecture 10 | - [How Wix manages Schemas for Kafka (and gRPC) used by 2000 microservices](https://medium.com/wix-engineering/how-wix-manages-schemas-for-kafka-and-grpc-used-by-2000-microservices-2117416ea17b) 11 | - [Spring Cloud Data Flow: The Core Components](https://www.zaloni.com/resources/blogs/the-core-components-of-spring-cloud-data-flow/) 12 | - [Spring boot starter for gRPC framework](https://github.com/LogNet/grpc-spring-boot-starter) 13 | ## Testing 14 | - [Mockk All the Things](https://jivimberg.io/blog/2019/05/09/mockk-features-rundown/) 15 | -------------------------------------------------------------------------------- /docs/community/contribution.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: contribution 3 | title: Contribution Guide 4 | description: Contribution Guide 5 | keywords: 6 | - Java 7 | - micro-apps 8 | - Framework 9 | - Microservices 10 | - Protobuf 11 | - gRPC 12 | - REST 13 | --- 14 | 15 | ### Guidelines 16 | - [Best Practices in Spring Boot Project Structure](https://www.codewithnk.com/post/best-practices-in-spring-boot-project-structure) 17 | -------------------------------------------------------------------------------- /docs/concepts/intro.md: -------------------------------------------------------------------------------- 1 | # Intro 2 | 3 | - [Release](./release.md) 4 | - [Versioning](./versioning.md) 5 | - [Monorepos](./monorepo.md) 6 | -------------------------------------------------------------------------------- /docs/concepts/monorepo.md: -------------------------------------------------------------------------------- 1 | # Monorepos 2 | 3 | `Monorepo` encourages developers to split monolith codebase into microservices and microapps, and manage them in single 4 | repository so that we can effortlessly keep all sub-modules in sync with consistent dependencies and versions. Developer 5 | can share code via `lib` modules. 6 | 7 | All `app` modules that includes `application` and `springboot` gradle plugins will automatically enabled for 8 | containerization with [Jib](https://github.com/GoogleContainerTools/jib) 9 | 10 | #### Testing 11 | 12 | This `Monorepo` template project is test framework agnostic. You can use `Spek`, `JUnit` or `Spock` Framework. 13 | 14 | #### Deploy 15 | 16 | you can build `Docker` and [OCI](https://github.com/opencontainers/image-spec) images 17 | with [Jib](https://github.com/GoogleContainerTools/jib) and deploy to `Kubernetes` 18 | 19 | #### Polyglot 20 | 21 | Each module can use your choice of JVM languages. Supports Java, Groovy, Kotlin, Scala. 22 | -------------------------------------------------------------------------------- /docs/concepts/release.md: -------------------------------------------------------------------------------- 1 | # Release 2 | 3 | ## Making Releases -------------------------------------------------------------------------------- /docs/concepts/testing.md: -------------------------------------------------------------------------------- 1 | # Testing 2 | 3 | - [Testing Koin applications with Kotest](https://dev.to/kerooker/testing-koin-applications-with-kotlintest-1iip) 4 | - [Mockk All the Things](https://jivimberg.io/blog/2019/05/09/mockk-features-rundown/) 5 | -------------------------------------------------------------------------------- /docs/devops/skaffold.md: -------------------------------------------------------------------------------- 1 | # Skaffold 2 | 3 | 4 | ## Install 5 | 6 | ```bash 7 | brew install skaffold 8 | ``` 9 | 10 | ## Setup 11 | 12 | ```bash 13 | skaffold init --XXenableBuildpacksInit 14 | # or 15 | skaffold init \ 16 | -a '{"builder":"buildpacks","payload":{"path":"leeroy-app/Dockerfile"},"image":"gcr.io/k8s-skaffold/leeroy-app"}' \ 17 | -a '{"builder":"buildpacks","payload":{"path":"leeroy-web/Dockerfile"},"image":"gcr.io/k8s-skaffold/leeroy-web","context":"path/to/context"}' 18 | ``` 19 | 20 | ## Use 21 | 22 | ```bash 23 | skaffold dev --port-forward 24 | ``` 25 | 26 | ## Reference 27 | 28 | - [Spring Boot on Kubernetes with Buildpacks and Skaffold](https://piotrminkowski.com/2020/12/18/spring-boot-on-kubernetes-with-buildpacks-and-skaffold/) 29 | -------------------------------------------------------------------------------- /docs/images/GitFlowDevelopBranch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmlking/micro-apps/135c0f6b8ccfe17121a367bbfdd8024c77ea3c51/docs/images/GitFlowDevelopBranch.png -------------------------------------------------------------------------------- /docs/images/GitFlowFeatureBranches.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmlking/micro-apps/135c0f6b8ccfe17121a367bbfdd8024c77ea3c51/docs/images/GitFlowFeatureBranches.png -------------------------------------------------------------------------------- /docs/images/GitFlowFull.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmlking/micro-apps/135c0f6b8ccfe17121a367bbfdd8024c77ea3c51/docs/images/GitFlowFull.png -------------------------------------------------------------------------------- /docs/images/GitFlowHotfixBranch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmlking/micro-apps/135c0f6b8ccfe17121a367bbfdd8024c77ea3c51/docs/images/GitFlowHotfixBranch.png -------------------------------------------------------------------------------- /docs/images/GitFlowMasterBranch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmlking/micro-apps/135c0f6b8ccfe17121a367bbfdd8024c77ea3c51/docs/images/GitFlowMasterBranch.png -------------------------------------------------------------------------------- /docs/images/GitFlowReleaseBranch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmlking/micro-apps/135c0f6b8ccfe17121a367bbfdd8024c77ea3c51/docs/images/GitFlowReleaseBranch.png -------------------------------------------------------------------------------- /docs/images/GitFlowWorkflowNoFork.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmlking/micro-apps/135c0f6b8ccfe17121a367bbfdd8024c77ea3c51/docs/images/GitFlowWorkflowNoFork.png -------------------------------------------------------------------------------- /docs/images/active-active-behind.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmlking/micro-apps/135c0f6b8ccfe17121a367bbfdd8024c77ea3c51/docs/images/active-active-behind.png -------------------------------------------------------------------------------- /docs/images/branches-overview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmlking/micro-apps/135c0f6b8ccfe17121a367bbfdd8024c77ea3c51/docs/images/branches-overview.png -------------------------------------------------------------------------------- /docs/images/chat-app.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmlking/micro-apps/135c0f6b8ccfe17121a367bbfdd8024c77ea3c51/docs/images/chat-app.png -------------------------------------------------------------------------------- /docs/images/end-to-end-google-cloud-devops-flow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmlking/micro-apps/135c0f6b8ccfe17121a367bbfdd8024c77ea3c51/docs/images/end-to-end-google-cloud-devops-flow.png -------------------------------------------------------------------------------- /docs/images/git-flow-commands.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmlking/micro-apps/135c0f6b8ccfe17121a367bbfdd8024c77ea3c51/docs/images/git-flow-commands.png -------------------------------------------------------------------------------- /docs/images/gitflow-overview.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmlking/micro-apps/135c0f6b8ccfe17121a367bbfdd8024c77ea3c51/docs/images/gitflow-overview.webp -------------------------------------------------------------------------------- /docs/images/monolith-microservices.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmlking/micro-apps/135c0f6b8ccfe17121a367bbfdd8024c77ea3c51/docs/images/monolith-microservices.png -------------------------------------------------------------------------------- /docs/images/opentelemetry_architecture.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmlking/micro-apps/135c0f6b8ccfe17121a367bbfdd8024c77ea3c51/docs/images/opentelemetry_architecture.webp -------------------------------------------------------------------------------- /docs/images/opentelemetry_java_instrument.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmlking/micro-apps/135c0f6b8ccfe17121a367bbfdd8024c77ea3c51/docs/images/opentelemetry_java_instrument.webp -------------------------------------------------------------------------------- /docs/images/pipeline-develop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmlking/micro-apps/135c0f6b8ccfe17121a367bbfdd8024c77ea3c51/docs/images/pipeline-develop.png -------------------------------------------------------------------------------- /docs/images/pipeline-feature.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmlking/micro-apps/135c0f6b8ccfe17121a367bbfdd8024c77ea3c51/docs/images/pipeline-feature.png -------------------------------------------------------------------------------- /docs/images/pipeline-master.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmlking/micro-apps/135c0f6b8ccfe17121a367bbfdd8024c77ea3c51/docs/images/pipeline-master.png -------------------------------------------------------------------------------- /docs/recipes/recipe2.md: -------------------------------------------------------------------------------- 1 | # Recipe 2 -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmlking/micro-apps/135c0f6b8ccfe17121a367bbfdd8024c77ea3c51/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /infra/benthos/README.md: -------------------------------------------------------------------------------- 1 | # Benthos 2 | 3 | **[Benthos](https://www.benthos.dev/)** is simple but powerful ETL tool. 4 | 5 | ## Setup 6 | 7 | ```bash 8 | # Install 9 | brew install benthos 10 | 11 | # Make a config 12 | benthos create nats/protobuf/aws_sqs > ./config.yaml 13 | 14 | # Run 15 | benthos -c ./config.yaml 16 | ``` 17 | 18 | Use **benthos** [Lab UX](https://lab.benthos.dev/l/wEeWzz0O1G0) to visualize the [config.yaml](./config.yaml) 19 | 20 | ## Raw Data 21 | 22 | Download full NPI data from [cms](https://download.cms.gov/nppes/NPI_Files.html) to load into Redis. 23 | 24 | Here I am including few records from downloaded **npidata_pfile_20050523-20210613.csv(8.27GB)** file as [npidata.csv](./npidata.csv) 25 | 26 | ## Commands 27 | 28 | ```bash 29 | #echo config 30 | benthos -c config.yaml echo 31 | 32 | #count input lines. Should be 135 33 | wc -l npidata.csv 34 | 35 | # run job 36 | benthos -c config.yaml 37 | 38 | #count output lines. Should be 100 39 | wc -l npidata.jsonl 40 | ``` 41 | -------------------------------------------------------------------------------- /infra/bindings/ca-certificates/my-corp-proxy.pem: -------------------------------------------------------------------------------- 1 | TODO: Add your corp proxy server's Cert here 2 | -------------------------------------------------------------------------------- /infra/bindings/ca-certificates/type: -------------------------------------------------------------------------------- 1 | ca-certificates 2 | -------------------------------------------------------------------------------- /infra/db_scripts/1-schema.sql: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmlking/micro-apps/135c0f6b8ccfe17121a367bbfdd8024c77ea3c51/infra/db_scripts/1-schema.sql -------------------------------------------------------------------------------- /infra/dgraph.yml: -------------------------------------------------------------------------------- 1 | version: "3.9" 2 | 3 | services: 4 | 5 | zero1: 6 | image: dgraph/dgraph:latest 7 | working_dir: /data/zero1 8 | labels: 9 | cluster: test 10 | ports: 11 | - "5080" 12 | - "6080" 13 | command: dgraph zero --my=zero1:5080 --idx=1 --logtostderr -v=2 --replicas 1 14 | 15 | alpha1: 16 | image: dgraph/dgraph:latest 17 | working_dir: /data/alpha1 18 | labels: 19 | cluster: test 20 | ports: 21 | - "8080:8080" 22 | - "9080:9080" 23 | command: dgraph alpha --my=alpha1:7080 --zero=zero1:5080 --logtostderr -v=2 --whitelist "10.0.0.0/8,172.16.0.0/12,192.168.0.0/16" 24 | 25 | ratel: 26 | image: dgraph/dgraph:latest 27 | ports: 28 | - 8000:8000 29 | command: dgraph-ratel 30 | 31 | volumes: { } 32 | -------------------------------------------------------------------------------- /infra/grafana/provisioning/datasources/redis.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: 1 2 | 3 | datasources: 4 | - name: Redis 5 | type: redis-datasource 6 | typeLogoUrl: public/plugins/redis-datasource/img/logo.svg 7 | access: proxy 8 | orgId: 1 9 | isDefault: true 10 | version: 1 11 | url: redis://redis:6379 12 | jsonData: 13 | poolSize: 5 14 | timeout: 10 15 | pingInterval: 0 16 | pipelineWindow: 0 17 | editable: true 18 | - name: Redis Cloud 19 | type: redis-datasource 20 | typeLogoUrl: public/plugins/redis-datasource/img/logo.svg 21 | access: proxy 22 | orgId: 1 23 | isDefault: false 24 | version: 1 25 | url: redis://$REDIS_CLOUD_HOST 26 | secureJsonData: 27 | password: $REDIS_CLOUD_PASSWORD 28 | # tlsCACert: "..." 29 | # tlsClientCert: "..." 30 | # tlsClientKey: "..." 31 | jsonData: 32 | acl: true 33 | user: asumo 34 | poolSize: 5 35 | timeout: 10 36 | pingInterval: 0 37 | pipelineWindow: 0 38 | editable: true 39 | -------------------------------------------------------------------------------- /infra/kafka/connectors/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmlking/micro-apps/135c0f6b8ccfe17121a367bbfdd8024c77ea3c51/infra/kafka/connectors/.gitkeep -------------------------------------------------------------------------------- /infra/kafka/sql/init.sql: -------------------------------------------------------------------------------- 1 | CREATE STREAM emergencies (name VARCHAR, reason VARCHAR, area VARCHAR) 2 | WITH (kafka_topic='call-center', value_format='json', partitions=1); 3 | 4 | 5 | CREATE TABLE location_of_interest AS 6 | SELECT reason, 7 | count_distinct(area) AS distinct_pings, 8 | latest_by_offset(area) AS last_location 9 | FROM emergencies 10 | GROUP BY reason 11 | EMIT CHANGES; 12 | 13 | 14 | CREATE TABLE call_record AS 15 | SELECT name, 16 | count(reason) AS total_emergencies 17 | FROM emergencies 18 | GROUP BY name 19 | EMIT CHANGES; 20 | -------------------------------------------------------------------------------- /infra/kafka/sql/query-example.sql: -------------------------------------------------------------------------------- 1 | 2 | SELECT * FROM call_record 3 | WHERE name = 'Louise' EMIT CHANGES; 4 | 5 | SELECT * FROM location_of_interest 6 | WHERE reason = 'allergy'; 7 | -------------------------------------------------------------------------------- /infra/kafka/udf/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmlking/micro-apps/135c0f6b8ccfe17121a367bbfdd8024c77ea3c51/infra/kafka/udf/.gitkeep -------------------------------------------------------------------------------- /infra/mssql.yml: -------------------------------------------------------------------------------- 1 | version: "3.9" 2 | 3 | services: 4 | 5 | mssql: 6 | # image: mcr.microsoft.com/mssql/server:2022-latest 7 | # platform: linux/amd64 8 | image: mcr.microsoft.com/azure-sql-edge:latest 9 | environment: 10 | - ACCEPT_EULA=Y 11 | - MSSQL_USER=SA 12 | - MSSQL_SA_PASSWORD=Passw@rd 13 | - MSSQL_PID=Developer 14 | ports: 15 | - '1433:1433' 16 | volumes: 17 | - mssql_data:/var/opt/mssql 18 | 19 | volumes: 20 | mssql_data: 21 | -------------------------------------------------------------------------------- /infra/postgres.yml: -------------------------------------------------------------------------------- 1 | version: "3.9" 2 | 3 | services: 4 | 5 | postgres: 6 | image: postgres:15 7 | restart: always 8 | ports: 9 | - '5432:5432' 10 | environment: 11 | POSTGRES_USER: postgres 12 | POSTGRES_PASSWORD: postgres 13 | POSTGRES_DB: postgresdb 14 | volumes: 15 | - db_data:/var/lib/postgresql/data 16 | - ./infra/db_scripts/init-database.sh:/docker-entrypoint-initdb.d/init-database.sh 17 | healthcheck: 18 | test: ['CMD-SHELL', 'pg_isready -U postgres'] 19 | interval: 5s 20 | timeout: 5s 21 | retries: 5 22 | command: > 23 | -c ssl=on 24 | -c ssl_cert_file=/etc/ssl/certs/ssl-cert-snakeoil.pem 25 | -c ssl_key_file=/etc/ssl/private/ssl-cert-snakeoil.key 26 | 27 | volumes: 28 | db_data: 29 | -------------------------------------------------------------------------------- /libs/avro/build.gradle.kts: -------------------------------------------------------------------------------- 1 | val avroVersion = libs.versions.avro.get() 2 | 3 | dependencies { 4 | implementation(projects.libs.core) 5 | implementation("org.apache.avro:avro:$avroVersion") 6 | // Testing 7 | testImplementation(testFixtures(projects.libs.test)) 8 | testImplementation(libs.kotlinx.coroutines.test) 9 | } 10 | 11 | affectedTestConfiguration { jvmTestTask = "check" } 12 | -------------------------------------------------------------------------------- /libs/avro/src/test/resources/account.avro: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmlking/micro-apps/135c0f6b8ccfe17121a367bbfdd8024c77ea3c51/libs/avro/src/test/resources/account.avro -------------------------------------------------------------------------------- /libs/core/build.gradle.kts: -------------------------------------------------------------------------------- 1 | description = "Core Lib module" 2 | 3 | // Test 4 | dependencies { 5 | // Testing 6 | testImplementation(testFixtures(projects.libs.test)) 7 | testImplementation(libs.kotlinx.coroutines.test) 8 | } 9 | 10 | affectedTestConfiguration { jvmTestTask = "check" } 11 | -------------------------------------------------------------------------------- /libs/core/src/main/kotlin/micro/apps/core/compose.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.core 2 | 3 | typealias Predicate = (T) -> Boolean 4 | 5 | infix fun Predicate.and(f: Predicate): Predicate = { x: A -> this(x) && f(x) } 6 | infix fun Predicate.or(f: Predicate): Predicate = { x: A -> this(x) || f(x) } 7 | // inline infix fun Predicate.or(crossinline f: Predicate): Predicate = { x: A -> this(x) || f(x) } 8 | -------------------------------------------------------------------------------- /libs/core/src/main/kotlin/micro/apps/core/tuples.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.core 2 | 3 | import java.io.Serializable 4 | 5 | data class Quadruple( 6 | val first: A, 7 | val second: B, 8 | val third: C, 9 | val fourth: D 10 | ) : Serializable { 11 | override fun toString(): String = "($first, $second, $third, $fourth)" 12 | } 13 | 14 | data class Quintuple( 15 | val first: A, 16 | val second: B, 17 | val third: C, 18 | val fourth: D, 19 | val fifth: E 20 | ) : Serializable { 21 | override fun toString(): String = "($first, $second, $third, $fourth, $fifth)" 22 | } 23 | -------------------------------------------------------------------------------- /libs/core/src/main/kotlin/micro/apps/core/utils.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.core 2 | 3 | import java.io.ByteArrayOutputStream 4 | import java.nio.charset.StandardCharsets.UTF_8 5 | import java.util.zip.GZIPInputStream 6 | import java.util.zip.GZIPOutputStream 7 | 8 | /** 9 | * Decompress a Gzip-compressed byte array 10 | * @param data Data to decompress 11 | */ 12 | fun decompressGzip(data: ByteArray): String { 13 | return GZIPInputStream(data.inputStream()).bufferedReader(UTF_8).use { it.readText() } 14 | } 15 | 16 | /** 17 | * Compress a string to Gzip 18 | * @param data Data to compress 19 | */ 20 | fun compressGzip(data: String): ByteArray { 21 | val os = ByteArrayOutputStream() 22 | GZIPOutputStream(os).bufferedWriter(UTF_8).use { it.write(data) } 23 | return os.toByteArray() 24 | } 25 | -------------------------------------------------------------------------------- /libs/core/src/main/resources/META-INF/beans.xml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmlking/micro-apps/135c0f6b8ccfe17121a367bbfdd8024c77ea3c51/libs/core/src/main/resources/META-INF/beans.xml -------------------------------------------------------------------------------- /libs/core/src/test/kotlin/micro/apps/core/ExtensionsTest.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.core 2 | 3 | import io.kotest.core.spec.style.FunSpec 4 | import io.kotest.matchers.shouldBe 5 | import java.time.Instant 6 | 7 | class ExtensionsTest : FunSpec({ 8 | test("Test toISO8601 extension of Instant") { 9 | val timestamp: Instant = Instant.parse("1995-10-23T10:12:35Z") 10 | timestamp.toISO8601() shouldBe "1995-10-23T10:12:35.000Z" 11 | } 12 | }) 13 | -------------------------------------------------------------------------------- /libs/crypto/build.gradle.kts: -------------------------------------------------------------------------------- 1 | val tinkVersion = libs.versions.googleTink.get() 2 | 3 | dependencies { 4 | implementation(projects.libs.core) 5 | implementation("com.google.crypto.tink:tink:$tinkVersion") 6 | // Optional 7 | implementation("com.google.crypto.tink:tink-gcpkms:$tinkVersion") 8 | // implementation("com.google.crypto.tink:tink-awskms:$tinkVersion") 9 | // FIXME: temp workaround https://github.com/google/tink/issues/549 10 | implementation("com.google.http-client:google-http-client-jackson2:1.43.2") 11 | 12 | // Testing 13 | testImplementation(testFixtures(projects.libs.test)) 14 | testImplementation(libs.kotlinx.coroutines.test) 15 | } 16 | 17 | affectedTestConfiguration { jvmTestTask = "check" } 18 | -------------------------------------------------------------------------------- /libs/graphql/README.md: -------------------------------------------------------------------------------- 1 | # Spring GraphQL Components 2 | 3 | This `GraphQL Service Lib module` contains **shared** code for all **Spring Boot GraphQL Services** 4 | 5 | Any duplicate business logic code from all **Spring GraphQL Services** in `services/***` should be centralized in this module. 6 | 7 | > Note: code here is not reusable beyond this workspace domain. 8 | 9 | ### Test 10 | 11 | ```bash 12 | gradle libs:graphql:test 13 | ``` 14 | 15 | ### Build 16 | 17 | ```bash 18 | gradle libs:graphql:clean 19 | gradle libs:graphql:build 20 | ``` 21 | -------------------------------------------------------------------------------- /libs/graphql/build.gradle.kts: -------------------------------------------------------------------------------- 1 | @Suppress("DSL_SCOPE_VIOLATION") // TODO remove when https://youtrack.jetbrains.com/issue/KTIJ-19369 is fixed 2 | plugins { 3 | alias(libs.plugins.kotlin.spring) 4 | 5 | alias(libs.plugins.spring.boot) 6 | alias(libs.plugins.spring.dependencyManagement) 7 | 8 | `java-test-fixtures` 9 | } 10 | 11 | dependencies { 12 | implementation(projects.libs.core) 13 | // Spring 14 | implementation(libs.bundles.spring.graphql) 15 | // Test 16 | testImplementation(testFixtures(projects.libs.test)) 17 | testImplementation(libs.spring.boot.starter.test) { 18 | exclude(module = "mockito-core") 19 | } 20 | testImplementation(libs.spring.boot.reactor.test) 21 | testImplementation(libs.spring.boot.mockk.test) 22 | testImplementation(libs.kotest.assertions.json.jvm) 23 | testImplementation(libs.kotest.extensions.spring) 24 | } 25 | 26 | tasks { 27 | bootJar { 28 | enabled = false 29 | } 30 | 31 | jar { 32 | enabled = true 33 | } 34 | } 35 | 36 | affectedTestConfiguration { jvmTestTask = "check" } 37 | -------------------------------------------------------------------------------- /libs/graphql/src/main/kotlin/micro/apps/service/directive/CapitalizeDirective.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.service.directive 2 | 3 | import graphql.schema.DataFetchingEnvironment 4 | import micro.apps.core.capitalize 5 | 6 | class CapitalizeDirective : StringFormatDirective() { 7 | override fun format(env: DataFetchingEnvironment, value: String): String { 8 | return value.capitalize(env.locale) 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /libs/graphql/src/main/kotlin/micro/apps/service/directive/LowercaseDirective.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.service.directive 2 | 3 | import graphql.schema.DataFetchingEnvironment 4 | 5 | class LowercaseDirective : StringFormatDirective() { 6 | override fun format(env: DataFetchingEnvironment, value: String): String { 7 | return value.lowercase(env.locale) 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /libs/graphql/src/main/kotlin/micro/apps/service/directive/SchemaDirective.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.service.directive 2 | 3 | import graphql.schema.idl.SchemaDirectiveWiring 4 | 5 | data class SchemaDirective( 6 | var name: String, 7 | var directive: SchemaDirectiveWiring 8 | ) 9 | -------------------------------------------------------------------------------- /libs/graphql/src/main/kotlin/micro/apps/service/directive/TrimDirective.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.service.directive 2 | 3 | import graphql.schema.DataFetchingEnvironment 4 | 5 | class TrimDirective : StringFormatDirective() { 6 | override fun format(env: DataFetchingEnvironment, value: String): String { 7 | return value.trim() 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /libs/graphql/src/main/kotlin/micro/apps/service/directive/UppercaseDirective.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.service.directive 2 | 3 | import graphql.schema.DataFetchingEnvironment 4 | 5 | class UppercaseDirective : StringFormatDirective() { 6 | override fun format(env: DataFetchingEnvironment, value: String): String { 7 | return value.uppercase(env.locale) 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /libs/graphql/src/test/kotlin/micro/apps/service/util/ExtensionsTest.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.service.util 2 | 3 | import io.kotest.core.spec.style.FunSpec 4 | import io.kotest.matchers.shouldBe 5 | import micro.apps.core.capitalize 6 | import java.util.Locale 7 | 8 | class ExtensionsTest : FunSpec({ 9 | test("capitalize string with locale") { 10 | val sumo = "sumo".capitalize(Locale.Builder().setLanguage("en").setRegion("US").build()) 11 | sumo shouldBe "Sumo" 12 | } 13 | }) 14 | -------------------------------------------------------------------------------- /libs/grpc/README.md: -------------------------------------------------------------------------------- 1 | # gRPC 2 | 3 | gRPC lib contains **shared** code for all **gRPC Services** 4 | 5 | Any duplicate business logic code from all **gRPC** in `apps/***-service` should be centralized in this module. 6 | 7 | > Note: code here is not reusable beyond this workspace domain. 8 | 9 | ### Test 10 | 11 | ```bash 12 | gradle libs:grpc:test 13 | ``` 14 | 15 | ### Build 16 | 17 | ```bash 18 | gradle libs:grpc:clean 19 | gradle libs:grpc:build 20 | ``` 21 | -------------------------------------------------------------------------------- /libs/grpc/src/main/kotlin/micro/apps/service/utils.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.service 2 | 3 | import com.alibaba.csp.sentinel.adapter.grpc.SentinelGrpcClientInterceptor 4 | import io.grpc.ChannelCredentials 5 | import io.grpc.Grpc 6 | import io.grpc.InsecureChannelCredentials 7 | import io.grpc.ManagedChannel 8 | 9 | fun channelForTarget(target: String, creds: ChannelCredentials = InsecureChannelCredentials.create()): ManagedChannel { 10 | return Grpc.newChannelBuilder(target, creds) 11 | /* Only for using provided test certs. */ 12 | .overrideAuthority("www.sumo.com") 13 | // .defaultLoadBalancingPolicy("round_robin") 14 | // .executor(Dispatchers.Default.asExecutor()) 15 | .build() 16 | } 17 | 18 | fun sentinelChannelForTarget( 19 | target: String, 20 | creds: ChannelCredentials = InsecureChannelCredentials.create() 21 | ): ManagedChannel { 22 | return Grpc.newChannelBuilder(target, creds) 23 | .defaultLoadBalancingPolicy("round_robin") 24 | .intercept(SentinelGrpcClientInterceptor()) 25 | .build() 26 | } 27 | -------------------------------------------------------------------------------- /libs/grpc/src/main/resources/META-INF/beans.xml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmlking/micro-apps/135c0f6b8ccfe17121a367bbfdd8024c77ea3c51/libs/grpc/src/main/resources/META-INF/beans.xml -------------------------------------------------------------------------------- /libs/grpc/src/test/kotlin/micro/apps/service/UtilsTest.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.service 2 | 3 | import io.kotest.core.spec.style.FunSpec 4 | import io.kotest.matchers.shouldBe 5 | 6 | class UtilsTest : FunSpec({ 7 | test("Dum should add") { 8 | 5 + 4 shouldBe 9 9 | } 10 | }) 11 | -------------------------------------------------------------------------------- /libs/kbeam/README.md: -------------------------------------------------------------------------------- 1 | # kbeam Lib 2 | 3 | [Apache Beam](https://beam.apache.org/) Kotlin extensions, DSL 4 | 5 | ### Run 6 | 7 | ```bash 8 | gradle :libs:kbeam:clean 9 | ``` 10 | 11 | ### Test 12 | 13 | ```bash 14 | gradle :libs:kbeam:test 15 | ``` 16 | 17 | ### Build 18 | 19 | ```bash 20 | gradle :libs:kbeam:build 21 | ``` 22 | 23 | ### Reference 24 | 25 | - [Idiomatic Kotlin Pipelines for Apache Beam](https://github.com/sfeir-open-source/kbeam) 26 | - [Beam Kotlin Examples](https://github.com/apache/beam/tree/master/examples/kotlin) 27 | 28 | ### Alternatives 29 | 30 | - [Kio](https://github.com/chermenin/kio) is a set of Kotlin extensions for [Apache Beam](https://beam.apache.org/) to implement fluent-like API for Java SDK. 31 | -------------------------------------------------------------------------------- /libs/kbeam/build.gradle.kts: -------------------------------------------------------------------------------- 1 | val junitVersion = libs.versions.junit.get() 2 | 3 | dependencies { 4 | // Use Apache Beam 5 | implementation(libs.beam.sdks.java.core) 6 | implementation(libs.beam.runners.direct.java) 7 | implementation(libs.beam.sdks.java.io.google.cloud.platform) 8 | 9 | // Test with JUnit4 & JUnit5 10 | testImplementation(kotlin("test")) 11 | testRuntimeOnly("org.junit.vintage:junit-vintage-engine:$junitVersion") { 12 | because("allows JUnit 4 tests run along with JUnit 5") 13 | } 14 | testImplementation(libs.hamcrest.all.test) 15 | testImplementation(libs.beam.sdks.java.extensions.json.jackson) 16 | } 17 | 18 | affectedTestConfiguration { jvmTestTask = "check" } 19 | -------------------------------------------------------------------------------- /libs/kbeam/src/main/kotlin/micro/apps/kbeam/Partition.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.kbeam 2 | 3 | import org.apache.beam.sdk.transforms.Partition 4 | import org.apache.beam.sdk.values.PCollection 5 | import org.apache.beam.sdk.values.PCollectionList 6 | 7 | inline fun PCollection.partition( 8 | nPartitions: Int, 9 | crossinline function: (item: I) -> Int 10 | ): PCollectionList { 11 | return this.apply( 12 | Partition.of(nPartitions) { item, _ -> 13 | function(item) 14 | } 15 | ) 16 | } 17 | -------------------------------------------------------------------------------- /libs/kbeam/src/main/kotlin/micro/apps/kbeam/coders/KryoCoder.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.kbeam.coders 2 | 3 | // import org.apache.beam.sdk.extensions.kryo.KryoCoderProvider 4 | 5 | // https://beam.apache.org/documentation/sdks/java/euphoria/ 6 | class KryoCoderProvider 7 | -------------------------------------------------------------------------------- /libs/kbeam/src/main/kotlin/micro/apps/kbeam/gcp/PubSub.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.kbeam.gcp 2 | 3 | import org.apache.beam.sdk.io.gcp.pubsub.PubsubIO 4 | import org.apache.beam.sdk.io.gcp.pubsub.PubsubMessage 5 | import org.apache.beam.sdk.values.PCollection 6 | import org.apache.beam.sdk.values.PDone 7 | 8 | /** 9 | * Write data to a PubSub topic. 10 | */ 11 | fun PCollection.toPubSub( 12 | name: String = "Write to PubSub", 13 | topic: String, 14 | idAttribute: String?, 15 | maxBatchSize: Int? = 10 16 | ): PDone { 17 | return this.apply( 18 | name, 19 | PubsubIO.writeMessages().to(topic).apply { 20 | maxBatchSize?.let { withMaxBatchSize(maxBatchSize) } 21 | idAttribute?.let { withIdAttribute(idAttribute) } 22 | } 23 | ) 24 | } 25 | -------------------------------------------------------------------------------- /libs/kbeam/src/main/kotlin/micro/apps/kbeam/gcp/Spanner.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.kbeam.gcp 2 | 3 | import com.google.cloud.spanner.Mutation 4 | import org.apache.beam.sdk.io.gcp.spanner.SpannerIO 5 | import org.apache.beam.sdk.values.PCollection 6 | 7 | /** 8 | * Write data to a Spanner table. 9 | */ 10 | fun PCollection.toSpanner( 11 | name: String = "Write to Spanner", 12 | instanceId: String, 13 | databaseId: String, 14 | batchSizeBytes: Long = (1024 * 10) 15 | ) { 16 | this.apply( 17 | name, 18 | SpannerIO.write() 19 | .withInstanceId(instanceId) 20 | .withDatabaseId(databaseId) 21 | .withBatchSizeBytes(batchSizeBytes) 22 | ) 23 | } 24 | -------------------------------------------------------------------------------- /libs/kbeam/src/main/resources/shared_application.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmlking/micro-apps/135c0f6b8ccfe17121a367bbfdd8024c77ea3c51/libs/kbeam/src/main/resources/shared_application.properties -------------------------------------------------------------------------------- /libs/kbeam/src/test/java/micro/apps/kbeam/MyOptions.java: -------------------------------------------------------------------------------- 1 | package micro.apps.kbeam; 2 | 3 | 4 | import org.apache.beam.sdk.options.Default; 5 | import org.apache.beam.sdk.options.Description; 6 | import org.apache.beam.sdk.options.PipelineOptions; 7 | 8 | public interface MyOptions extends PipelineOptions { 9 | @Description("Custom Option") 10 | @Default.String("test") 11 | String getTest(); 12 | 13 | void setTest(String test); 14 | } 15 | -------------------------------------------------------------------------------- /libs/kbeam/src/test/resources/application.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmlking/micro-apps/135c0f6b8ccfe17121a367bbfdd8024c77ea3c51/libs/kbeam/src/test/resources/application.properties -------------------------------------------------------------------------------- /libs/kbeam/src/test/resources/data/test.csv: -------------------------------------------------------------------------------- 1 | Truc,FR,4.55 2 | Machin,DE,3.33 3 | Chose,GB,-2 4 | -------------------------------------------------------------------------------- /libs/kstream/src/main/kotlin/micro/apps/kstream/KSerdes.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.kstream 2 | 3 | import org.apache.kafka.common.serialization.Serde 4 | import org.apache.kafka.common.serialization.Serdes.serdeFrom 5 | import org.apache.kafka.streams.kstream.Consumed 6 | import org.apache.kafka.streams.kstream.Grouped 7 | import org.apache.kafka.streams.kstream.Produced 8 | 9 | object KSerdes { 10 | @DslMarker 11 | annotation class KStreamsDsl 12 | 13 | @KStreamsDsl 14 | inline fun grouped(): Grouped = 15 | Grouped.with(serdeFrom(K::class.java), serdeFrom(V::class.java)) 16 | 17 | @KStreamsDsl 18 | inline fun consumedWith(): Consumed = 19 | Consumed.with(serdeFrom(K::class.java), serdeFrom(V::class.java)) 20 | 21 | @KStreamsDsl 22 | inline fun producedWith(): Produced = 23 | Produced.with(serdeFrom(K::class.java), serdeFrom(V::class.java)) 24 | 25 | @KStreamsDsl 26 | inline fun producedWith(serde: Serde): Produced = 27 | Produced.with(serdeFrom(K::class.java), serde) 28 | } 29 | -------------------------------------------------------------------------------- /libs/kstream/src/main/kotlin/micro/apps/kstream/serializer/CryptoKafkaAvro4kDeserializerConfig.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.kstream.serializer 2 | 3 | import org.apache.kafka.common.config.ConfigDef 4 | 5 | class CryptoKafkaAvro4kDeserializerConfig(props: Map) : AbstractCryptoKafkaAvro4kSerDeConfig( 6 | baseConfigDef().define( 7 | RECORD_PACKAGES, 8 | ConfigDef.Type.STRING, 9 | null, 10 | ConfigDef.Importance.HIGH, 11 | "The packages in which record types annotated with @AvroName, @AvroAlias and @AvroNamespace can be found. Packages are separated by a colon ','." 12 | ), 13 | props 14 | ) { 15 | 16 | fun getRecordPackages() = getString(RECORD_PACKAGES)?.split(",")?.map { it.trim() }?.toList() ?: emptyList() 17 | 18 | companion object { 19 | const val RECORD_PACKAGES = "record.packages" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /libs/kstream/src/main/kotlin/micro/apps/kstream/serializer/CryptoKafkaAvro4kSerializerConfig.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.kstream.serializer 2 | 3 | class CryptoKafkaAvro4kSerializerConfig(props: Map) : AbstractCryptoKafkaAvro4kSerDeConfig(baseConfigDef(), props) 4 | -------------------------------------------------------------------------------- /libs/kstream/src/test/kotlin/micro/apps/kstream/ExtensionsTest.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.kstream 2 | 3 | import io.kotest.core.spec.style.FunSpec 4 | 5 | class ExtensionsTest : FunSpec({ 6 | test("Test grouped extension of Grouped") { 7 | // TODO() 8 | } 9 | }) 10 | -------------------------------------------------------------------------------- /libs/model/README.md: -------------------------------------------------------------------------------- 1 | # Model 2 | 3 | This module contains only models. 4 | 5 | Convention is to keep `model` module not to depend on 3rd party dependencies except `serialization`. Contain data 6 | classes used across multiple `apps`. All `model` serializable to `JSON`, `Avro` and `ProtoBuf` 7 | 8 | ### Run 9 | 10 | ```bash 11 | gradle libs:model:clean -Prelease.forceVersion=3.0.0 12 | ``` 13 | 14 | ### Test 15 | 16 | ```bash 17 | gradle libs:model:test 18 | ``` 19 | 20 | ### Build 21 | 22 | ```bash 23 | gradle libs:model:build 24 | ``` 25 | 26 | -------------------------------------------------------------------------------- /libs/model/src/main/resources/META-INF/beans.xml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmlking/micro-apps/135c0f6b8ccfe17121a367bbfdd8024c77ea3c51/libs/model/src/main/resources/META-INF/beans.xml -------------------------------------------------------------------------------- /libs/model/src/test/resources/data/pizzas.avro: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmlking/micro-apps/135c0f6b8ccfe17121a367bbfdd8024c77ea3c51/libs/model/src/test/resources/data/pizzas.avro -------------------------------------------------------------------------------- /libs/model/src/test/resources/data/pizzas.avsc: -------------------------------------------------------------------------------- 1 | { 2 | "type" : "record", 3 | "name" : "Pizza", 4 | "namespace" : "micro.apps.model", 5 | "fields" : [ { 6 | "name" : "name", 7 | "type" : "string" 8 | }, { 9 | "name" : "ingredients", 10 | "type" : { 11 | "type" : "array", 12 | "items" : { 13 | "type" : "record", 14 | "name" : "Ingredient", 15 | "fields" : [ { 16 | "name" : "name", 17 | "type" : "string" 18 | }, { 19 | "name" : "sugar", 20 | "type" : "double" 21 | }, { 22 | "name" : "fat", 23 | "type" : "double" 24 | } ] 25 | } 26 | } 27 | }, { 28 | "name" : "vegetarian", 29 | "type" : "boolean" 30 | }, { 31 | "name" : "kcals", 32 | "type" : "int" 33 | } ] 34 | } 35 | -------------------------------------------------------------------------------- /libs/pipeline/README.md: -------------------------------------------------------------------------------- 1 | # Pipeline 2 | 3 | `Pipeline Lib module` contains **shared** non-reusable code for all **Pipelines** 4 | 5 | Any duplicate business logic code from all `apps/***-pipeline` should be centralized in this module 6 | 7 | > Note: code here is not reusable beyond this workspace domain. 8 | 9 | ### Test 10 | 11 | ```bash 12 | gradle libs:pipeline:test 13 | ``` 14 | 15 | ### Build 16 | 17 | ```bash 18 | gradle libs:pipeline:clean 19 | gradle libs:pipeline:build 20 | ``` 21 | -------------------------------------------------------------------------------- /libs/pipeline/build.gradle.kts: -------------------------------------------------------------------------------- 1 | val junitVersion = libs.versions.junit.get() 2 | val slf4jVersion = libs.versions.slf4j.get() 3 | 4 | plugins { 5 | `java-test-fixtures` 6 | } 7 | 8 | dependencies { 9 | // Use Apache Beam 10 | implementation(libs.bundles.beam) 11 | 12 | // Test with JUnit4 & JUnit5 13 | testImplementation(kotlin("test")) 14 | 15 | testRuntimeOnly("org.junit.vintage:junit-vintage-engine:$junitVersion") { 16 | because("allows JUnit 4 tests run along with JUnit 5") 17 | } 18 | testImplementation(libs.hamcrest.all.test) 19 | testImplementation(libs.kotlinx.coroutines.test) 20 | testImplementation(testFixtures(projects.libs.test)) 21 | testFixturesImplementation(libs.google.cloud.pubsub) 22 | } 23 | 24 | affectedTestConfiguration { jvmTestTask = "check" } 25 | -------------------------------------------------------------------------------- /libs/pipeline/src/main/kotlin/micro/apps/pipeline/coders/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmlking/micro-apps/135c0f6b8ccfe17121a367bbfdd8024c77ea3c51/libs/pipeline/src/main/kotlin/micro/apps/pipeline/coders/.gitkeep -------------------------------------------------------------------------------- /libs/pipeline/src/main/kotlin/micro/apps/pipeline/config/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmlking/micro-apps/135c0f6b8ccfe17121a367bbfdd8024c77ea3c51/libs/pipeline/src/main/kotlin/micro/apps/pipeline/config/.gitkeep -------------------------------------------------------------------------------- /libs/pipeline/src/main/kotlin/micro/apps/pipeline/constants.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.pipeline 2 | 3 | import org.apache.avro.generic.GenericRecord 4 | import org.apache.beam.sdk.values.TupleTag 5 | 6 | val successTag = object : TupleTag() {} 7 | val errorTag = object : TupleTag() {} 8 | -------------------------------------------------------------------------------- /libs/pipeline/src/main/kotlin/micro/apps/pipeline/transforms/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmlking/micro-apps/135c0f6b8ccfe17121a367bbfdd8024c77ea3c51/libs/pipeline/src/main/kotlin/micro/apps/pipeline/transforms/.gitkeep -------------------------------------------------------------------------------- /libs/pipeline/src/main/kotlin/micro/apps/pipeline/utils.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.pipeline 2 | 3 | fun sum(a: Int, b: Int) = a + b 4 | -------------------------------------------------------------------------------- /libs/pipeline/src/main/resources/META-INF/beans.xml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmlking/micro-apps/135c0f6b8ccfe17121a367bbfdd8024c77ea3c51/libs/pipeline/src/main/resources/META-INF/beans.xml -------------------------------------------------------------------------------- /libs/pipeline/src/test/kotlin/micro/apps/pipeline/UtilsTest.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.pipeline 2 | 3 | import io.kotest.core.spec.style.FunSpec 4 | import io.kotest.matchers.shouldBe 5 | 6 | class UtilsTest : FunSpec({ 7 | test("Dum should add") { 8 | sum(5, 4) shouldBe 9 9 | } 10 | }) 11 | -------------------------------------------------------------------------------- /libs/proto/src/main/kotlin/micro/apps/proto/common/v1/errors.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.proto.common.v1 2 | 3 | typealias PersonId = String 4 | typealias ProductId = String 5 | typealias OrderId = String 6 | 7 | class DuplicateCustomerIdException(personId: PersonId) : RuntimeException("A person with id $personId already exist") 8 | class DuplicateProductIdException(productId: ProductId) : RuntimeException("A product with id $productId already exist") 9 | class DuplicateOrderIdException(orderId: OrderId) : RuntimeException("An order with id $orderId already exist") 10 | -------------------------------------------------------------------------------- /libs/proto/src/main/kotlin/micro/apps/proto/util/PersonFieldMasks.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.proto.util 2 | 3 | import com.google.protobuf.FieldMask 4 | import com.google.protobuf.util.FieldMaskUtil 5 | import micro.apps.proto.common.v1.Person 6 | 7 | // TODO: https://netflixtechblog.com/practical-api-design-at-netflix-part-1-using-protobuf-fieldmask-35cfdc606518 8 | 9 | object PersonFieldMasks { 10 | /** 11 | * Can be used in [GetPersonRequest] to query 12 | * production title and format 13 | */ 14 | val FIRST_AND_LAST_NAME_FIELD_MASK: FieldMask = FieldMaskUtil.fromFieldNumbers( 15 | Person::class.java, 16 | Person.FIRST_NAME_FIELD_NUMBER, 17 | Person.LAST_NAME_FIELD_NUMBER 18 | ) 19 | 20 | /** 21 | * Can be used in [GetPersonRequest] to query 22 | * production title and schedule 23 | */ 24 | val PHONE_AND_EMAIL_FIELD_MASK: FieldMask = FieldMaskUtil.fromFieldNumbers( 25 | Person::class.java, 26 | Person.PHONE_FIELD_NUMBER, 27 | Person.EMAIL_FIELD_NUMBER 28 | ) 29 | } 30 | -------------------------------------------------------------------------------- /libs/proto/src/main/proto/buf.lock: -------------------------------------------------------------------------------- 1 | # Generated by buf. DO NOT EDIT. 2 | version: v1 3 | deps: 4 | - remote: buf.build 5 | owner: googleapis 6 | repository: googleapis 7 | branch: main 8 | commit: 3acb5846ac62425ea63964d3a02db72f 9 | digest: b1-H-YZn4iL6Z89CPrbe2RMpz3xiQuiA-uXRRvOS-4-03g= 10 | create_time: 2021-12-18T15:02:51.352987Z 11 | - remote: buf.build 12 | owner: srikrsna 13 | repository: protoc-gen-gotag 14 | branch: main 15 | commit: 8b63cc254bb545328abd56041a1b928d 16 | digest: b1-BDhD5LflQs3pzPcMS8d_c7oRsFGbIElgp1R-kKaJXP8= 17 | create_time: 2021-08-06T16:50:16.793881Z 18 | -------------------------------------------------------------------------------- /libs/proto/src/main/proto/micro/apps/proto/echo/v1/echo.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package micro.apps.proto.echo.v1; 4 | 5 | option java_multiple_files = true; 6 | option java_outer_classname = "EchoServiceProto"; 7 | option java_package = "micro.apps.proto.echo.v1"; 8 | 9 | service EchoService { 10 | rpc Echo(EchoRequest) returns (EchoResponse); 11 | rpc EchoStream(EchoStreamRequest) returns (stream EchoStreamResponse) {} 12 | } 13 | 14 | message EchoRequest { 15 | string message = 1; 16 | } 17 | 18 | message EchoResponse { 19 | string message = 1; 20 | } 21 | 22 | message EchoStreamRequest { 23 | string message = 1; 24 | } 25 | 26 | message EchoStreamResponse { 27 | string message = 1; 28 | } 29 | -------------------------------------------------------------------------------- /libs/proto/src/main/proto/micro/apps/proto/keying/v1/keying.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package micro.apps.proto.keying.v1; 4 | 5 | option java_multiple_files = true; 6 | option java_outer_classname = "KeyingServiceProto"; 7 | option java_package = "micro.apps.proto.keying.v1"; 8 | 9 | import "micro/apps/proto/common/v1/common.proto"; 10 | 11 | service KeyingService { 12 | rpc Key(KeyRequest) returns (KeyResponse); 13 | rpc KeyStream(stream KeyRequest) returns (stream KeyResponse) {} 14 | } 15 | 16 | message KeyRequest { 17 | micro.apps.proto.common.v1.Profile profile = 1; 18 | oneof entity { 19 | micro.apps.proto.common.v1.Person person = 2; 20 | micro.apps.proto.common.v1.Address address = 3; 21 | } 22 | } 23 | 24 | message KeyResponse { 25 | optional string key = 1; 26 | micro.apps.proto.common.v1.Status status = 2; 27 | } 28 | -------------------------------------------------------------------------------- /libs/proto/src/main/proto/micro/apps/proto/linking/v1/linking.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package micro.apps.proto.linking.v1; 4 | 5 | option java_multiple_files = true; 6 | option java_outer_classname = "LinkingServiceProto"; 7 | option java_package = "micro.apps.proto.linking.v1"; 8 | 9 | import "micro/apps/proto/common/v1/common.proto"; 10 | 11 | service LinkingService { 12 | rpc Link(LinkRequest) returns (LinkResponse); 13 | rpc LinkStream(stream LinkRequest) returns (stream LinkResponse) {} 14 | } 15 | 16 | message LinkRequest { 17 | micro.apps.proto.common.v1.Profile profile = 1; 18 | micro.apps.proto.common.v1.Person person = 2; 19 | repeated micro.apps.proto.common.v1.Address addresses = 3; 20 | } 21 | 22 | message LinkResponse { 23 | optional string person_id = 1; 24 | micro.apps.proto.common.v1.Status status = 2; 25 | } 26 | -------------------------------------------------------------------------------- /libs/proto/src/main/resources/META-INF/beans.xml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmlking/micro-apps/135c0f6b8ccfe17121a367bbfdd8024c77ea3c51/libs/proto/src/main/resources/META-INF/beans.xml -------------------------------------------------------------------------------- /libs/proto/src/main/third_party_proto/buf.yaml: -------------------------------------------------------------------------------- 1 | version: v1 2 | 3 | lint: 4 | ignore: 5 | - validate 6 | -------------------------------------------------------------------------------- /libs/proto/src/test/kotlin/micro/apps/proto/account/AccountKtTest.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.proto.account 2 | 3 | import io.kotest.core.spec.style.FunSpec 4 | import io.kotest.matchers.shouldBe 5 | import micro.apps.proto.common.v1.person 6 | 7 | class AccountKtTest : FunSpec({ 8 | 9 | test("Person proto generated class should be buildable") { 10 | val person = person { 11 | firstName = "sumo" 12 | lastName = "demo" 13 | phone = "000-000-0000" 14 | } 15 | person.email.isEmpty() shouldBe true 16 | person.firstName shouldBe "sumo" 17 | } 18 | }) 19 | -------------------------------------------------------------------------------- /libs/proto/src/test/kotlin/micro/apps/proto/echo/EchoKtTest.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.proto.echo 2 | 3 | import io.kotest.core.spec.style.FunSpec 4 | import io.kotest.matchers.shouldBe 5 | import micro.apps.proto.echo.v1.echoRequest 6 | import mu.KotlinLogging 7 | 8 | private val logger = KotlinLogging.logger {} 9 | class EchoKtTest : FunSpec({ 10 | 11 | test("EchoRequest proto generated class should be buildable") { 12 | val echo = echoRequest { 13 | message = "sumo" 14 | } 15 | logger.atDebug().addArgument(echo).log("In EchoKtTest") 16 | echo.message shouldBe "sumo" 17 | } 18 | }) 19 | -------------------------------------------------------------------------------- /libs/proto/src/testFixtures/kotlin/micro/apps/proto/account/fixtures/mock-account.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.proto.account.fixtures 2 | 3 | import micro.apps.proto.account.v1.CreateRequest 4 | import micro.apps.proto.account.v1.createRequest 5 | import micro.apps.proto.common.fixtures.mockPerson 6 | 7 | fun mockAccountCreateRequest(mockId: Int): CreateRequest { 8 | return createRequest { account = mockPerson(mockId) } 9 | } 10 | -------------------------------------------------------------------------------- /libs/spring/README.md: -------------------------------------------------------------------------------- 1 | # Spring Shared Components 2 | 3 | This `Micro Service Lib module` contains **shared** code for all **Spring Boot REST Services** 4 | 5 | Any duplicate business logic code from all **Spring REST Services** in `services/***` should be centralized in this module. 6 | 7 | > Note: code here is not reusable beyond this workspace domain. 8 | 9 | ### Test 10 | 11 | ```bash 12 | gradle libs:spring:test 13 | ``` 14 | 15 | ### Build 16 | 17 | ```bash 18 | gradle libs:spring:clean 19 | gradle libs:spring:build 20 | ``` 21 | -------------------------------------------------------------------------------- /libs/spring/src/main/kotlin/micro/apps/service/CrudService.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.service 2 | 3 | import kotlinx.coroutines.flow.Flow 4 | 5 | interface CrudService { 6 | suspend fun get(id: String): T 7 | suspend fun getAll(): Flow 8 | suspend fun update(id: String, dto: D): T 9 | suspend fun update(obg: T): T 10 | suspend fun create(obg: D): T 11 | suspend fun delete(id: String) 12 | } 13 | -------------------------------------------------------------------------------- /libs/spring/src/main/kotlin/micro/apps/service/EventBus.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.service 2 | 3 | import kotlinx.coroutines.flow.MutableSharedFlow 4 | import kotlinx.coroutines.flow.asSharedFlow 5 | 6 | class EventBus { 7 | private val _events = MutableSharedFlow() // private mutable shared flow 8 | val events = _events.asSharedFlow() // publicly exposed as read-only shared flow 9 | 10 | suspend fun produceEvent(event: T) { 11 | _events.emit(event) // suspends until all subscribers receive it 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /libs/spring/src/main/kotlin/micro/apps/service/exceptions.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.service 2 | 3 | import org.springframework.http.HttpStatus 4 | import org.springframework.http.HttpStatus.NOT_FOUND 5 | import org.springframework.web.bind.annotation.ResponseStatus 6 | 7 | /*** Exceptions ***/ 8 | 9 | @ResponseStatus(value = NOT_FOUND, reason = "No such Record") 10 | class RecordNotFoundException(override val message: String) : RuntimeException(message) 11 | 12 | // based on import org.springframework.dao.DuplicateKeyException 13 | @ResponseStatus(value = HttpStatus.CONFLICT, reason = "Duplicate Id") 14 | class DuplicateKeyException(id: String, type: String?) : RuntimeException("A ${type ?: "record"} with id $id already exist") 15 | 16 | @ResponseStatus(value = HttpStatus.TOO_MANY_REQUESTS, reason = "Rate limit exceeded") 17 | class RateLimitExceededException : RuntimeException("Rate limit exceeded") 18 | -------------------------------------------------------------------------------- /libs/spring/src/test/kotlin/micro/apps/service/UtilsTest.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.service 2 | 3 | import io.kotest.core.spec.style.FunSpec 4 | import io.kotest.matchers.shouldBe 5 | 6 | class UtilsTest : FunSpec({ 7 | test("Dum should add") { 8 | 5 + 4 shouldBe 9 9 | } 10 | }) 11 | -------------------------------------------------------------------------------- /libs/test/README.md: -------------------------------------------------------------------------------- 1 | # Test-Utils 2 | 3 | Test Utils Lib module. 4 | 5 | contains test helper functions, fixtures and `kotest` tags etc 6 | 7 | ### Usage 8 | 9 | import it as `testImplementation` in your `build.gradle.kts` 10 | 11 | ```gradle 12 | testImplementation(testFixtures(projects.libs.test)) 13 | ``` 14 | 15 | ### Test 16 | 17 | ```bash 18 | gradle libs:test:test 19 | ``` 20 | 21 | ### Build 22 | 23 | ```bash 24 | gradle libs:test:build 25 | ``` 26 | -------------------------------------------------------------------------------- /libs/test/build.gradle.kts: -------------------------------------------------------------------------------- 1 | val kotestVersion: String by project 2 | 3 | plugins { 4 | // which produces test fixtures 5 | `java-test-fixtures` 6 | } 7 | 8 | dependencies { 9 | testFixturesImplementation(libs.kotest.runner.junit5.jvm) 10 | } 11 | 12 | affectedTestConfiguration { jvmTestTask = "check" } 13 | -------------------------------------------------------------------------------- /libs/test/src/testFixtures/kotlin/micro/apps/model/fixtures/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmlking/micro-apps/135c0f6b8ccfe17121a367bbfdd8024c77ea3c51/libs/test/src/testFixtures/kotlin/micro/apps/model/fixtures/.gitkeep -------------------------------------------------------------------------------- /libs/test/src/testFixtures/kotlin/micro/apps/test/tags.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.test 2 | 3 | import io.kotest.core.Tag 4 | 5 | object Slow : Tag() 6 | object Mock : Tag() 7 | object E2E : Tag() 8 | object gRPC : Tag() 9 | -------------------------------------------------------------------------------- /pipelines/classifier/src/main/kotlin/micro/apps/pipeline/ClassifierOptions.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.pipeline 2 | 3 | import org.apache.beam.sdk.options.Default 4 | import org.apache.beam.sdk.options.Description 5 | 6 | interface ClassifierOptions : BaseStreamingOptions { 7 | @get:Description( 8 | """The window duration in which data will be written. Defaults to 5m. 9 | Allowed formats are: 10 | Ns (for seconds, example: 5s), 11 | Nm (for minutes, example: 12m), 12 | Nh (for hours, example: 2h).")""" 13 | ) 14 | @get:Default.String("300s") 15 | var windowDuration: String 16 | } 17 | -------------------------------------------------------------------------------- /pipelines/classifier/src/main/resources/config.prod.yaml: -------------------------------------------------------------------------------- 1 | certs: 2 | serverKey: certs/server-key.pem 3 | serverCert: certs/server-cert.pem 4 | clientKey: certs/client-key.pem 5 | clientCert: certs/client-cert.pem 6 | caCert: certs/ca-cert.pem 7 | account: 8 | endpoint: 127.0.0.1:8080 9 | authority: my.domain.com 10 | maxRetry: 3 11 | deadline: 3s 12 | endpoints: 13 | account: 127.0.0.2:8080 14 | echo: 127.0.0.3:8080 15 | cloud: 16 | dataflow: 17 | windowDuration: 300s 18 | -------------------------------------------------------------------------------- /pipelines/classifier/src/main/resources/config.yaml: -------------------------------------------------------------------------------- 1 | certs: 2 | serverKey: certs/server-key.pem 3 | serverCert: certs/server-cert.pem 4 | clientKey: certs/client-key.pem 5 | clientCert: certs/client-cert.pem 6 | caCert: certs/ca-cert.pem 7 | account: 8 | endpoint: 127.0.0.1:8080 9 | authority: my.domain.com 10 | maxRetry: 3 11 | deadline: 2s 12 | endpoints: 13 | account: 127.0.0.2:8080 14 | echo: 127.0.0.3:8080 15 | cloud: 16 | dataflow: 17 | windowDuration: 500s 18 | -------------------------------------------------------------------------------- /pipelines/classifier/src/main/resources/data/person.avro: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmlking/micro-apps/135c0f6b8ccfe17121a367bbfdd8024c77ea3c51/pipelines/classifier/src/main/resources/data/person.avro -------------------------------------------------------------------------------- /pipelines/classifier/src/main/resources/logging.properties: -------------------------------------------------------------------------------- 1 | ############################################################ 2 | # Global properties 3 | ############################################################ 4 | handlers=java.util.logging.ConsoleHandler 5 | .level=INFO 6 | ############################################################ 7 | # Handler specific properties. 8 | # Describes specific configuration info for Handlers. 9 | ############################################################ 10 | java.util.logging.ConsoleHandler.level=ALL 11 | java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter 12 | java.util.logging.SimpleFormatter.format=%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS %4$s %2$s %5$s%6$s%n 13 | ############################################################ 14 | # Facility specific properties. 15 | # Provides extra control for each logger. 16 | ############################################################ 17 | micro.apps.level=INFO 18 | -------------------------------------------------------------------------------- /pipelines/classifier/src/test/resources/data/person.avro: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmlking/micro-apps/135c0f6b8ccfe17121a367bbfdd8024c77ea3c51/pipelines/classifier/src/test/resources/data/person.avro -------------------------------------------------------------------------------- /pipelines/classifier/src/test/resources/logging.properties: -------------------------------------------------------------------------------- 1 | ############################################################ 2 | # Global properties 3 | ############################################################ 4 | handlers=java.util.logging.ConsoleHandler 5 | .level=INFO 6 | ############################################################ 7 | # Handler specific properties. 8 | # Describes specific configuration info for Handlers. 9 | ############################################################ 10 | java.util.logging.ConsoleHandler.level=ALL 11 | java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter 12 | java.util.logging.SimpleFormatter.format=%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS %4$s %2$s %5$s%6$s%n 13 | ############################################################ 14 | # Facility specific properties. 15 | # Provides extra control for each logger. 16 | ############################################################ 17 | micro.apps.level=INFO 18 | -------------------------------------------------------------------------------- /pipelines/ingestion/src/main/resources/config.prod.yaml: -------------------------------------------------------------------------------- 1 | certs: 2 | serverKey: certs/server-key.pem 3 | serverCert: certs/server-cert.pem 4 | clientKey: certs/client-key.pem 5 | clientCert: certs/client-cert.pem 6 | caCert: certs/ca-cert.pem 7 | account: 8 | endpoint: 127.0.0.1:8080 9 | authority: my.domain.com 10 | maxRetry: 3 11 | deadline: 3s 12 | endpoints: 13 | account: 127.0.0.2:8080 14 | echo: 127.0.0.3:8080 15 | cloud: 16 | dataflow: 17 | windowDuration: 300s 18 | -------------------------------------------------------------------------------- /pipelines/ingestion/src/main/resources/config.yaml: -------------------------------------------------------------------------------- 1 | certs: 2 | serverKey: certs/server-key.pem 3 | serverCert: certs/server-cert.pem 4 | clientKey: certs/client-key.pem 5 | clientCert: certs/client-cert.pem 6 | caCert: certs/ca-cert.pem 7 | account: 8 | endpoint: 127.0.0.1:8080 9 | authority: my.domain.com 10 | maxRetry: 3 11 | deadline: 2s 12 | endpoints: 13 | account: 127.0.0.2:8080 14 | echo: 127.0.0.3:8080 15 | cloud: 16 | dataflow: 17 | windowDuration: 500s 18 | -------------------------------------------------------------------------------- /pipelines/ingestion/src/main/resources/data/person.avro: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmlking/micro-apps/135c0f6b8ccfe17121a367bbfdd8024c77ea3c51/pipelines/ingestion/src/main/resources/data/person.avro -------------------------------------------------------------------------------- /pipelines/ingestion/src/main/resources/logging.properties: -------------------------------------------------------------------------------- 1 | ############################################################ 2 | # Global properties 3 | ############################################################ 4 | handlers=java.util.logging.ConsoleHandler 5 | .level=INFO 6 | ############################################################ 7 | # Handler specific properties. 8 | # Describes specific configuration info for Handlers. 9 | ############################################################ 10 | java.util.logging.ConsoleHandler.level=ALL 11 | java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter 12 | java.util.logging.SimpleFormatter.format=%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS %4$s %2$s %5$s%6$s%n 13 | ############################################################ 14 | # Facility specific properties. 15 | # Provides extra control for each logger. 16 | ############################################################ 17 | micro.apps.level=INFO 18 | -------------------------------------------------------------------------------- /pipelines/ingestion/src/test/resources/data/person.avro: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmlking/micro-apps/135c0f6b8ccfe17121a367bbfdd8024c77ea3c51/pipelines/ingestion/src/test/resources/data/person.avro -------------------------------------------------------------------------------- /pipelines/ingestion/src/test/resources/logging.properties: -------------------------------------------------------------------------------- 1 | ############################################################ 2 | # Global properties 3 | ############################################################ 4 | handlers=java.util.logging.ConsoleHandler 5 | .level=INFO 6 | ############################################################ 7 | # Handler specific properties. 8 | # Describes specific configuration info for Handlers. 9 | ############################################################ 10 | java.util.logging.ConsoleHandler.level=ALL 11 | java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter 12 | java.util.logging.SimpleFormatter.format=%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS %4$s %2$s %5$s%6$s%n 13 | ############################################################ 14 | # Facility specific properties. 15 | # Provides extra control for each logger. 16 | ############################################################ 17 | micro.apps.level=INFO 18 | -------------------------------------------------------------------------------- /pipelines/wordcount/src/main/resources/application.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmlking/micro-apps/135c0f6b8ccfe17121a367bbfdd8024c77ea3c51/pipelines/wordcount/src/main/resources/application.properties -------------------------------------------------------------------------------- /pipelines/wordcount/src/main/resources/logging.properties: -------------------------------------------------------------------------------- 1 | ############################################################ 2 | # Global properties 3 | ############################################################ 4 | handlers=java.util.logging.ConsoleHandler 5 | .level=INFO 6 | ############################################################ 7 | # Handler specific properties. 8 | # Describes specific configuration info for Handlers. 9 | ############################################################ 10 | java.util.logging.ConsoleHandler.level=ALL 11 | java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter 12 | java.util.logging.SimpleFormatter.format=%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS %4$s %2$s %5$s%6$s%n 13 | ############################################################ 14 | # Facility specific properties. 15 | # Provides extra control for each logger. 16 | ############################################################ 17 | micro.apps.level=INFO 18 | -------------------------------------------------------------------------------- /pipelines/wordcount/src/test/kotlin/micro/apps/pipeline/Junit5Test.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.pipeline 2 | 3 | import io.kotest.core.spec.style.FunSpec 4 | 5 | class Junit5Test : FunSpec({ 6 | 7 | beforeTest { 8 | println("Starting test ${it.name}!") 9 | } 10 | afterTest { 11 | println("Finished test ${it.a.name}!") 12 | } 13 | 14 | test("person should have message") { 15 | println("hi...") 16 | } 17 | }) 18 | -------------------------------------------------------------------------------- /pipelines/wordcount/src/test/resources/application.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmlking/micro-apps/135c0f6b8ccfe17121a367bbfdd8024c77ea3c51/pipelines/wordcount/src/test/resources/application.properties -------------------------------------------------------------------------------- /pipelines/wordcount/src/test/resources/data/input.txt: -------------------------------------------------------------------------------- 1 | KING OF FRANCE: 2 | 3 | DUKE OF BURGUNDY (BURGUNDY:) 4 | 5 | DUKE OF CORNWALL (CORNWALL:) 6 | 7 | DUKE OF ALBANY (ALBANY:) 8 | 9 | EARL OF KENT (KENT:) 10 | 11 | EARL OF GLOUCESTER (GLOUCESTER:) 12 | 13 | EDGAR son to Gloucester. 14 | 15 | EDMUND bastard son to Gloucester. 16 | 17 | CURAN a courtier. 18 | 19 | Old Man tenant to Gloucester. 20 | 21 | Doctor: 22 | 23 | Fool: 24 | 25 | OSWALD steward to Goneril. 26 | -------------------------------------------------------------------------------- /pipelines/wordcount/src/test/resources/logging.properties: -------------------------------------------------------------------------------- 1 | ############################################################ 2 | # Global properties 3 | ############################################################ 4 | handlers=java.util.logging.ConsoleHandler 5 | .level=INFO 6 | ############################################################ 7 | # Handler specific properties. 8 | # Describes specific configuration info for Handlers. 9 | ############################################################ 10 | java.util.logging.ConsoleHandler.level=ALL 11 | java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter 12 | java.util.logging.SimpleFormatter.format=%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS %4$s %2$s %5$s%6$s%n 13 | ############################################################ 14 | # Facility specific properties. 15 | # Provides extra control for each logger. 16 | ############################################################ 17 | micro.apps.level=INFO 18 | -------------------------------------------------------------------------------- /scripts/add-keycloak-db.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<-EOSQL 5 | CREATE USER keycloak WITH ENCRYPTED PASSWORD 'keycloak'; 6 | CREATE DATABASE keycloak; 7 | GRANT ALL PRIVILEGES ON DATABASE keycloak TO keycloak; 8 | EOSQL 9 | -------------------------------------------------------------------------------- /services/account/src/main/resources/config.prod.yaml: -------------------------------------------------------------------------------- 1 | certs: 2 | caCert: config/certs/ca-cert.pem 3 | clientKey: config/certs/client-key.pem 4 | clientCert: config/certs/client-cert.pem 5 | proxyKey: config/certs/proxy-key.pem 6 | proxyCert: config/certs/proxy-cert.pem 7 | upstreamKey: config/certs/upstream-key.pem 8 | upstreamCert: config/certs/upstream-cert.pem 9 | upstreamCaCert: config/certs/upstream-ca-cert.pem 10 | account: 11 | endpoint: 0.0.0.0:9444 12 | authority: www.sumo.com 13 | maxRetry: 3 14 | deadline: 3s 15 | endpoints: 16 | account: 127.0.0.2:8080 17 | echo: 127.0.0.3:8080 18 | -------------------------------------------------------------------------------- /services/account/src/main/resources/config.yaml: -------------------------------------------------------------------------------- 1 | certs: 2 | caCert: config/certs/ca-cert.pem 3 | clientKey: config/certs/client-key.pem 4 | clientCert: config/certs/client-cert.pem 5 | proxyKey: config/certs/proxy-key.pem 6 | proxyCert: config/certs/proxy-cert.pem 7 | upstreamKey: config/certs/upstream-localhost-key.pem 8 | upstreamCert: config/certs/upstream-localhost-cert.pem 9 | upstreamCaCert: config/certs/upstream-ca-cert.pem 10 | account: 11 | endpoint: 0.0.0.0:9444 12 | authority: www.sumo.com 13 | maxRetry: 3 14 | deadline: 2s 15 | endpoints: 16 | account: 127.0.0.2:8080 17 | echo: 127.0.0.3:8080 18 | -------------------------------------------------------------------------------- /services/account/src/main/resources/simplelogger.properties: -------------------------------------------------------------------------------- 1 | org.slf4j.simpleLogger.defaultLogLevel=info 2 | org.slf4j.simpleLogger.log.micro.apps=info 3 | -------------------------------------------------------------------------------- /services/account/src/test/resources/config.yaml: -------------------------------------------------------------------------------- 1 | certs: 2 | caCert: config/certs/upstream-ca-cert.pem 3 | clientKey: config/certs/client-key.pem 4 | clientCert: config/certs/client-cert.pem 5 | proxyKey: config/certs/proxy-key.pem 6 | proxyCert: config/certs/proxy-cert.pem 7 | upstreamKey: config/certs/upstream-localhost-key.pem 8 | upstreamCert: config/certs/upstream-localhost-cert.pem 9 | upstreamCaCert: config/certs/upstream-ca-cert.pem 10 | account: 11 | endpoint: 0.0.0.0:5001 12 | authority: localhost 13 | maxRetry: 3 14 | deadline: 2s 15 | endpoints: 16 | account: 127.0.0.2:8080 17 | echo: 127.0.0.3:8080 18 | -------------------------------------------------------------------------------- /services/account/src/test/resources/simplelogger.properties: -------------------------------------------------------------------------------- 1 | org.slf4j.simpleLogger.defaultLogLevel=info 2 | org.slf4j.simpleLogger.log.micro.apps=debug 3 | -------------------------------------------------------------------------------- /services/chat/README.md: -------------------------------------------------------------------------------- 1 | # Chat App 2 | 3 | **SpringBoot** app showcasing *Kotlin Coroutines* and *RSocket* 4 | 5 | ## Overview 6 | 7 |

8 | 9 |

10 | 11 | ## Run 12 | 13 | ```bash 14 | gradle :services:chat:bootRun 15 | # log at debug level 16 | gradle :services:chat:bootRun --debug 17 | ``` 18 | 19 | Open two browser tabs and start chatting... 20 | 21 | ```bash 22 | open http://localhost:8080/ 23 | ``` 24 | 25 | ## Build 26 | 27 | ### Build fatJar 28 | 29 | ```bash 30 | gradle :services:chat:build 31 | ``` 32 | 33 | ### Build native image 34 | 35 | ```bash 36 | gradle :services:chat:bootBuildImage 37 | ``` 38 | 39 | ### Reference 40 | 41 | * [Spring Boot with Kotlin and RSocket](https://spring.io/guides/tutorials/spring-webflux-kotlin-rsocket/) 42 | * [Original Repo](https://github.com/kotlin-hands-on/kotlin-spring-chat) 43 | -------------------------------------------------------------------------------- /services/chat/src/main/kotlin/micro/apps/service/controller/HtmlController.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.service.controller 2 | 3 | import org.springframework.stereotype.Controller 4 | import org.springframework.web.bind.annotation.GetMapping 5 | 6 | @Controller 7 | class HtmlController() { 8 | 9 | @GetMapping("/") 10 | fun index(): String { 11 | return "chatrs" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /services/chat/src/main/kotlin/micro/apps/service/controller/MessageResource.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.service.controller 2 | 3 | import kotlinx.coroutines.flow.Flow 4 | import kotlinx.coroutines.flow.emitAll 5 | import kotlinx.coroutines.flow.onStart 6 | import micro.apps.service.service.MessageService 7 | import micro.apps.service.service.MessageVM 8 | import org.springframework.messaging.handler.annotation.MessageMapping 9 | import org.springframework.messaging.handler.annotation.Payload 10 | import org.springframework.stereotype.Controller 11 | 12 | @Controller 13 | @MessageMapping("api.v1.messages") 14 | class MessageResource(val messageService: MessageService) { 15 | 16 | @MessageMapping("stream") 17 | suspend fun receive(@Payload inboundMessages: Flow) = 18 | messageService.post(inboundMessages) 19 | 20 | @MessageMapping("stream") 21 | fun send(): Flow = messageService 22 | .stream() 23 | .onStart { 24 | emitAll(messageService.latest()) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /services/chat/src/main/kotlin/micro/apps/service/repository/DomainModel.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.service.repository 2 | 3 | import org.springframework.data.annotation.Id 4 | import org.springframework.data.relational.core.mapping.Table 5 | import java.time.Instant 6 | 7 | @Table("MESSAGES") 8 | data class Message( 9 | val content: String, 10 | val contentType: ContentType, 11 | val sent: Instant, 12 | val username: String, 13 | val userAvatarImageLink: String, 14 | @Id var id: String? = null 15 | ) 16 | 17 | enum class ContentType { 18 | PLAIN, MARKDOWN 19 | } 20 | -------------------------------------------------------------------------------- /services/chat/src/main/kotlin/micro/apps/service/repository/MessageRepository.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.service.repository 2 | 3 | import kotlinx.coroutines.flow.Flow 4 | import org.springframework.data.r2dbc.repository.Query 5 | import org.springframework.data.repository.kotlin.CoroutineCrudRepository 6 | import org.springframework.data.repository.query.Param 7 | 8 | interface MessageRepository : CoroutineCrudRepository { 9 | 10 | // language=SQL 11 | @Query( 12 | """ 13 | SELECT * FROM ( 14 | SELECT * FROM MESSAGES 15 | ORDER BY "SENT" DESC 16 | LIMIT 10 17 | ) ORDER BY "SENT" 18 | """ 19 | ) 20 | fun findLatest(): Flow 21 | 22 | // language=SQL 23 | @Query( 24 | """ 25 | SELECT * FROM ( 26 | SELECT * FROM MESSAGES 27 | WHERE SENT > (SELECT SENT FROM MESSAGES WHERE ID = :id) 28 | ORDER BY "SENT" DESC 29 | ) ORDER BY "SENT" 30 | """ 31 | ) 32 | fun findLatest(@Param("id") id: String): Flow 33 | } 34 | -------------------------------------------------------------------------------- /services/chat/src/main/kotlin/micro/apps/service/service/MessageService.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.service.service 2 | 3 | import kotlinx.coroutines.flow.Flow 4 | 5 | interface MessageService { 6 | 7 | fun latest(): Flow 8 | 9 | fun after(messageId: String): Flow 10 | 11 | fun stream(): Flow 12 | 13 | suspend fun post(messages: Flow) 14 | } 15 | -------------------------------------------------------------------------------- /services/chat/src/main/kotlin/micro/apps/service/service/ViewModel.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.service.service 2 | 3 | import java.net.URL 4 | import java.time.Instant 5 | 6 | data class MessageVM(val content: String, val user: UserVM, val sent: Instant, val id: String? = null) 7 | 8 | data class UserVM(val name: String, val avatarImageLink: URL) 9 | -------------------------------------------------------------------------------- /services/chat/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.application.name = chat-service 2 | 3 | spring.r2dbc.url=r2dbc:h2:file:///./build/data/testdb;USER=sa;PASSWORD=password 4 | spring.rsocket.server.transport=websocket 5 | spring.rsocket.server.mapping-path=/rsocket 6 | -------------------------------------------------------------------------------- /services/chat/src/main/resources/sql/schema.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE IF NOT EXISTS messages 2 | ( 3 | id VARCHAR(60) DEFAULT RANDOM_UUID() PRIMARY KEY, 4 | content VARCHAR NOT NULL, 5 | content_type VARCHAR(128) NOT NULL, 6 | sent TIMESTAMP NOT NULL, 7 | username VARCHAR(60) NOT NULL, 8 | user_avatar_image_link VARCHAR(256) NOT NULL 9 | ); 10 | -------------------------------------------------------------------------------- /services/chat/src/test/kotlin/micro/apps/service/TestExtensions.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.service 2 | 3 | import micro.apps.service.repository.Message 4 | import micro.apps.service.service.MessageVM 5 | import java.time.temporal.ChronoUnit.MILLIS 6 | 7 | fun MessageVM.prepareForTesting() = copy(id = null, sent = sent.truncatedTo(MILLIS)) 8 | 9 | fun Message.prepareForTesting() = copy(id = null, sent = sent.truncatedTo(MILLIS)) 10 | -------------------------------------------------------------------------------- /services/entity/src/main/kotlin/micro/apps/service/config/AppConfig.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.service.config 2 | 3 | import org.springframework.boot.context.properties.EnableConfigurationProperties 4 | import org.springframework.context.annotation.Configuration 5 | 6 | @Configuration 7 | @EnableConfigurationProperties( 8 | value = [ 9 | ChangeEventProperties::class, 10 | MetricsProperties::class, 11 | ] 12 | ) 13 | class AppConfig 14 | -------------------------------------------------------------------------------- /services/entity/src/main/kotlin/micro/apps/service/config/SecurityConfig.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.service.config 2 | 3 | /* 4 | @EnableWebSecurity 5 | class SecurityConfig { 6 | 7 | @Bean 8 | fun filterChain(http: HttpSecurity): SecurityFilterChain { 9 | http { 10 | authorizeRequests { 11 | authorize(anyRequest, authenticated) 12 | } 13 | formLogin { } 14 | httpBasic { } 15 | } 16 | return http.build() 17 | } 18 | 19 | @Suppress("DEPRECATION") 20 | @Bean 21 | fun userDetailsService(): UserDetailsService { 22 | val user = User.withDefaultPasswordEncoder() 23 | .username("user") 24 | .password("password") 25 | .roles("USER") 26 | .build() 27 | return InMemoryUserDetailsManager(user) 28 | } 29 | } 30 | */ 31 | -------------------------------------------------------------------------------- /services/entity/src/main/kotlin/micro/apps/service/config/SwaggerConfig.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.service.config 2 | 3 | // @EnableSwagger2 4 | // @Configuration 5 | // class SwaggerConfig { 6 | // 7 | // @Bean 8 | // fun configureSwagger() = Docket(DocumentationType.SWAGGER_2) 9 | // .select() 10 | // .apis(RequestHandlerSelectors.any()) 11 | // .paths(regex("/v1/.*")) 12 | // .build() 13 | // } 14 | -------------------------------------------------------------------------------- /services/entity/src/main/kotlin/micro/apps/service/domain/account/AccountRepository.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.service.domain.account 2 | 3 | /* 4 | import kotlinx.serialization.ExperimentalSerializationApi 5 | import org.springframework.data.redis.core.RedisTemplate 6 | import org.springframework.data.repository.CrudRepository 7 | import org.springframework.stereotype.Repository 8 | import java.util.* 9 | 10 | 11 | @OptIn(ExperimentalSerializationApi::class) 12 | @Repository 13 | class AccountCustomRepository(val template: RedisTemplate) : CrudRepository { 14 | override fun findById(id: String): Optional { 15 | TODO() 16 | } 17 | } 18 | 19 | */ 20 | -------------------------------------------------------------------------------- /services/entity/src/main/kotlin/micro/apps/service/domain/account/extensions.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.service.domain.account 2 | 3 | import kotlinx.serialization.ExperimentalSerializationApi 4 | 5 | @OptIn(ExperimentalSerializationApi::class) 6 | fun PersonDto.toEntity(): PersonEntity { 7 | val addresses = this.addresses?.map { it.toEntity() }?.toSet() 8 | return PersonEntity(null, name, addresses, gender, dob, email, phone, avatar) 9 | } 10 | 11 | @OptIn(ExperimentalSerializationApi::class) 12 | fun AddressDto.toEntity() = 13 | AddressEntity(null, suite, street, city, state, code, country, location) 14 | -------------------------------------------------------------------------------- /services/entity/src/main/kotlin/micro/apps/service/domain/account/repositories.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.service.domain.account 2 | 3 | import kotlinx.serialization.ExperimentalSerializationApi 4 | import org.springframework.data.repository.PagingAndSortingRepository 5 | import org.springframework.stereotype.Repository 6 | 7 | /* 8 | * Note: Redis Repositories DO NOT work with transactions 9 | */ 10 | @OptIn(ExperimentalSerializationApi::class) 11 | @Repository 12 | // interface PersonRepository : ReactiveCrudRepository { 13 | // interface PersonRepository : CoroutineSortingRepository { 14 | interface PersonRepository : PagingAndSortingRepository 15 | 16 | @OptIn(ExperimentalSerializationApi::class) 17 | @Repository 18 | interface AddressRepository : PagingAndSortingRepository 19 | -------------------------------------------------------------------------------- /services/entity/src/main/kotlin/micro/apps/service/domain/product/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmlking/micro-apps/135c0f6b8ccfe17121a367bbfdd8024c77ea3c51/services/entity/src/main/kotlin/micro/apps/service/domain/product/.gitkeep -------------------------------------------------------------------------------- /services/entity/src/main/resources/application-production.yml: -------------------------------------------------------------------------------- 1 | spring.redis.url: localhost:6379 2 | 3 | spring.cloud.gcp.core.enabled: true 4 | # Recommend specifying project ID by the GOOGLE_CLOUD_PROJECT environment variable 5 | # spring.cloud.gcp.project-id: 6 | # Recommend specifying credentials file pointed by the GOOGLE_APPLICATION_CREDENTIALS environment variable 7 | # spring.cloud.gcp.credentials.location=file:/usr/local/key.json 8 | 9 | spring.cloud.gcp.logging.enabled: true 10 | spring.cloud.gcp.metrics.enabled: true 11 | 12 | management.metrics.export.stackdriver.enabled: true 13 | management.metrics.export.stackdriver.step: 5s 14 | 15 | # (optional) enable access to http://localhost:8080/actuator/metrics 16 | management.endpoints.web.exposure.include: metrics 17 | -------------------------------------------------------------------------------- /services/entity/src/main/resources/banner.txt: -------------------------------------------------------------------------------- 1 | ,------. ,--. ,--. ,--. 2 | | .---' ,--,--, ,-' '-. `--' ,-' '-. ,--. ,--. 3 | | `--, | \ '-. .-' ,--. '-. .-' \ ' / 4 | | `---. | || | | | | | | | \ ' 5 | `------' `--''--' `--' `--' `--' .-' / 6 | `---' 7 | -------------------------------------------------------------------------------- /services/entity/src/main/resources/logback-spring.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /services/entity/src/test/kotlin/micro/apps/service/EntityApplicationTest.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.service 2 | 3 | import io.kotest.core.spec.style.FunSpec 4 | import io.kotest.matchers.nulls.shouldNotBeNull 5 | import org.springframework.boot.test.context.SpringBootTest 6 | import org.springframework.core.env.Environment 7 | 8 | @SpringBootTest 9 | class EntityApplicationTest(private val environment: Environment) : FunSpec({ 10 | test("application starts") { 11 | environment.shouldNotBeNull() 12 | } 13 | }) 14 | -------------------------------------------------------------------------------- /services/entity/src/test/kotlin/micro/apps/service/ProjectConfig.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.service 2 | 3 | import io.kotest.core.config.AbstractProjectConfig 4 | import io.kotest.extensions.spring.SpringExtension 5 | 6 | class ProjectConfig : AbstractProjectConfig() { 7 | override fun extensions() = listOf(SpringExtension) 8 | } 9 | -------------------------------------------------------------------------------- /services/greeting/.dockerignore: -------------------------------------------------------------------------------- 1 | * 2 | !build/*-runner 3 | !build/*-runner.jar 4 | !build/lib/* 5 | !build/quarkus-app/* 6 | -------------------------------------------------------------------------------- /services/greeting/src/main/docker/Dockerfile.native: -------------------------------------------------------------------------------- 1 | #### 2 | # This Dockerfile is used in order to build a container that runs the Quarkus application in native (no JVM) mode 3 | # 4 | # Before building the container image run: 5 | # 6 | # ./gradlew build -Dquarkus.package.type=native 7 | # 8 | # Then, build the image with: 9 | # 10 | # docker build -f src/main/docker/Dockerfile.native -t quarkus/greeting-service . 11 | # 12 | # Then run the container using: 13 | # 14 | # docker run -i --rm -p 8080:8080 quarkus/greeting-service 15 | # 16 | ### 17 | FROM registry.access.redhat.com/ubi8/ubi-minimal:8.3 18 | WORKDIR /work/ 19 | RUN chown 1001 /work \ 20 | && chmod "g+rwX" /work \ 21 | && chown 1001:root /work 22 | COPY --chown=1001:root build/*-runner /work/application 23 | 24 | EXPOSE 8080 25 | USER 1001 26 | 27 | CMD ["./application", "-Dquarkus.http.host=0.0.0.0"] 28 | -------------------------------------------------------------------------------- /services/greeting/src/main/docker/Dockerfile.native-distroless: -------------------------------------------------------------------------------- 1 | #### 2 | # This Dockerfile is used in order to build a distroless container that runs the Quarkus application in native (no JVM) mode 3 | # 4 | # Before building the container image run: 5 | # 6 | # ./gradlew build -Dquarkus.package.type=native 7 | # 8 | # Then, build the image with: 9 | # 10 | # docker build -f src/main/docker/Dockerfile.native-distroless -t quarkus/greeting-service . 11 | # 12 | # Then run the container using: 13 | # 14 | # docker run -i --rm -p 8080:8080 quarkus/greeting-service 15 | # 16 | ### 17 | FROM quay.io/quarkus/quarkus-distroless-image:1.0 18 | COPY build/*-runner /application 19 | 20 | EXPOSE 8080 21 | USER nonroot 22 | 23 | CMD ["./application", "-Dquarkus.http.host=0.0.0.0"] 24 | -------------------------------------------------------------------------------- /services/greeting/src/main/kotlin/micro/apps/service/config/AppConfig.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.service.config 2 | 3 | import io.smallrye.config.ConfigMapping 4 | import org.eclipse.microprofile.config.inject.ConfigProperty 5 | 6 | @ConfigMapping(prefix = "greeting") 7 | interface AppConfig { 8 | @ConfigProperty(name = "application.name") 9 | fun applicationName(): String? 10 | } 11 | -------------------------------------------------------------------------------- /services/greeting/src/main/kotlin/micro/apps/service/domain/account/Account.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.service.domain.account 2 | 3 | import java.time.LocalDate 4 | 5 | // @Entity 6 | data class Account( 7 | var firstName: String?, 8 | var lastName: String? = null, 9 | var phoneNumber: String?, 10 | var birthdate: LocalDate? = null 11 | ) 12 | -------------------------------------------------------------------------------- /services/greeting/src/main/kotlin/micro/apps/service/domain/account/AccountDTO.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.service.domain.account 2 | 3 | import java.time.LocalDate 4 | 5 | data class AccountDTO( 6 | var firstName: String?, 7 | var lastName: String? = null, 8 | var phone: String?, 9 | var birthdate: LocalDate? = null 10 | ) 11 | -------------------------------------------------------------------------------- /services/greeting/src/main/kotlin/micro/apps/service/domain/account/AccountMapper.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.service.domain.account 2 | 3 | import micro.apps.service.util.IMapper 4 | import org.mapstruct.InheritInverseConfiguration 5 | import org.mapstruct.Mapper 6 | import org.mapstruct.Mapping 7 | import org.mapstruct.Mappings 8 | 9 | @Mapper(componentModel = "cdi") 10 | interface AccountMapper : IMapper { 11 | @Mappings( 12 | Mapping(source = "phoneNumber", target = "phone"), 13 | Mapping(source = "firstName", target = "firstName") 14 | ) 15 | override fun toDTO(entity: Account): AccountDTO 16 | 17 | @InheritInverseConfiguration 18 | override fun toEntity(dto: AccountDTO): Account 19 | } 20 | -------------------------------------------------------------------------------- /services/greeting/src/main/kotlin/micro/apps/service/domain/account/AccountRepository.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.service.domain.account 2 | 3 | import javax.enterprise.context.ApplicationScoped 4 | 5 | @ApplicationScoped 6 | class AccountRepository 7 | -------------------------------------------------------------------------------- /services/greeting/src/main/kotlin/micro/apps/service/domain/greeting/GreetingService.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.service.domain.greeting 2 | 3 | import micro.apps.model.Greeting 4 | import javax.enterprise.context.ApplicationScoped 5 | 6 | @ApplicationScoped 7 | class GreetingService { 8 | 9 | fun greeting(name: String): Greeting { 10 | return Greeting("hello, $name") 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /services/greeting/src/main/kotlin/micro/apps/service/util/IMapper.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.service.util 2 | 3 | interface IMapper { 4 | fun toEntity(dto: D): E 5 | fun toDTO(entity: E): D 6 | // fun toEntities(dtoList: List?): List? 7 | // fun toDTOs(entityList: List?): List? 8 | } 9 | 10 | fun IMapper.toEntities(dtoList: List): List { 11 | val result = mutableListOf() 12 | for (dto in dtoList) { 13 | result.add(toEntity(dto)) 14 | } 15 | return result 16 | } 17 | 18 | fun IMapper.toDTOs(entityList: List): List { 19 | val result = mutableListOf() 20 | for (entity in entityList) { 21 | result.add(toDTO(entity)) 22 | } 23 | return result 24 | } 25 | -------------------------------------------------------------------------------- /services/greeting/src/native-test/kotlin/micro/apps/service/NativeGreetingResourceIT.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.service 2 | 3 | import io.quarkus.test.junit.NativeImageTest 4 | import kotlin.time.ExperimentalTime 5 | 6 | @ExperimentalTime 7 | @NativeImageTest 8 | open class NativeGreetingResourceIT : GreetingResourceTest() 9 | -------------------------------------------------------------------------------- /services/greeting/src/test/kotlin/micro/apps/service/AccountServiceTest.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.service 2 | 3 | import io.kotest.core.spec.style.FunSpec 4 | import io.kotest.matchers.shouldBe 5 | import io.quarkus.test.junit.QuarkusTest 6 | import micro.apps.service.domain.account.AccountDTO 7 | import micro.apps.service.domain.account.AccountService 8 | import micro.apps.service.util.Failure 9 | import micro.apps.service.util.Success 10 | import javax.inject.Inject 11 | 12 | @QuarkusTest 13 | class AccountServiceTest : FunSpec() { 14 | 15 | @Inject 16 | lateinit var accountService: AccountService 17 | 18 | init { 19 | test("user service should be injected") { 20 | val result = accountService.findById("sumo") 21 | if (result is Failure) { 22 | // result.left shouldBe 23 | } else if (result is Success) { 24 | result.right.firstName shouldBe "firstName-sumo" 25 | } 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /services/greeting/src/test/kotlin/micro/apps/service/MockTest.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.service 2 | 3 | import io.kotest.core.spec.style.FunSpec 4 | import io.kotest.matchers.shouldBe 5 | import io.quarkus.test.junit.QuarkusTest 6 | import micro.apps.service.domain.greeting.GreetingService 7 | import javax.inject.Inject 8 | 9 | @QuarkusTest 10 | class MockTest : FunSpec() { 11 | 12 | @Inject 13 | lateinit var greetingService: GreetingService 14 | 15 | init { 16 | test("Should inject the mocked bean") { 17 | greetingService.greeting("sumo") shouldBe "Welcome" 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /services/greeting/src/test/kotlin/micro/apps/service/MockedService.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.service 2 | 3 | import io.quarkus.test.Mock 4 | import micro.apps.model.Greeting 5 | import micro.apps.service.domain.greeting.GreetingService 6 | import javax.enterprise.context.ApplicationScoped 7 | 8 | @Mock 9 | @ApplicationScoped 10 | class MockedService : GreetingService() { 11 | override fun greeting(name: String) = Greeting("Welcome") 12 | } 13 | -------------------------------------------------------------------------------- /services/greeting/src/test/kotlin/micro/apps/service/PropertiesTest.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.service 2 | 3 | import io.kotest.core.spec.style.FunSpec 4 | import io.kotest.matchers.shouldBe 5 | import io.quarkus.test.junit.QuarkusTest 6 | import org.eclipse.microprofile.config.inject.ConfigProperty 7 | 8 | @QuarkusTest 9 | class PropertiesTest : FunSpec() { 10 | 11 | @ConfigProperty(name = "test-foo") 12 | lateinit var testFoo: String 13 | 14 | init { 15 | test("Should load properties correctly") { 16 | testFoo shouldBe "bar" 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /services/greeting/src/test/resources/application.yaml: -------------------------------------------------------------------------------- 1 | test-foo: bar 2 | -------------------------------------------------------------------------------- /services/keying/src/main/resources/config.prod.yaml: -------------------------------------------------------------------------------- 1 | certs: 2 | caCert: config/certs/ca-cert.pem 3 | clientKey: config/certs/client-key.pem 4 | clientCert: config/certs/client-cert.pem 5 | proxyKey: config/certs/proxy-key.pem 6 | proxyCert: config/certs/proxy-cert.pem 7 | upstreamKey: config/certs/upstream-key.pem 8 | upstreamCert: config/certs/upstream-cert.pem 9 | upstreamCaCert: config/certs/upstream-ca-cert.pem 10 | account: 11 | endpoint: 0.0.0.0:9444 12 | authority: www.sumo.com 13 | maxRetry: 3 14 | deadline: 3s 15 | endpoints: 16 | account: 127.0.0.2:8080 17 | echo: 127.0.0.3:8080 18 | -------------------------------------------------------------------------------- /services/keying/src/main/resources/config.yaml: -------------------------------------------------------------------------------- 1 | certs: 2 | caCert: config/certs/ca-cert.pem 3 | clientKey: config/certs/client-key.pem 4 | clientCert: config/certs/client-cert.pem 5 | proxyKey: config/certs/proxy-key.pem 6 | proxyCert: config/certs/proxy-cert.pem 7 | upstreamKey: config/certs/upstream-localhost-key.pem 8 | upstreamCert: config/certs/upstream-localhost-cert.pem 9 | upstreamCaCert: config/certs/upstream-ca-cert.pem 10 | account: 11 | endpoint: 0.0.0.0:9444 12 | authority: www.sumo.com 13 | maxRetry: 3 14 | deadline: 2s 15 | endpoints: 16 | account: 127.0.0.2:8080 17 | echo: 127.0.0.3:8080 18 | -------------------------------------------------------------------------------- /services/keying/src/main/resources/simplelogger.properties: -------------------------------------------------------------------------------- 1 | org.slf4j.simpleLogger.defaultLogLevel=info 2 | org.slf4j.simpleLogger.log.micro.apps=info 3 | -------------------------------------------------------------------------------- /services/keying/src/test/resources/config.yaml: -------------------------------------------------------------------------------- 1 | certs: 2 | caCert: config/certs/upstream-ca-cert.pem 3 | clientKey: config/certs/client-key.pem 4 | clientCert: config/certs/client-cert.pem 5 | proxyKey: config/certs/proxy-key.pem 6 | proxyCert: config/certs/proxy-cert.pem 7 | upstreamKey: config/certs/upstream-localhost-key.pem 8 | upstreamCert: config/certs/upstream-localhost-cert.pem 9 | upstreamCaCert: config/certs/upstream-ca-cert.pem 10 | account: 11 | endpoint: 0.0.0.0:5002 12 | authority: localhost 13 | maxRetry: 3 14 | deadline: 2s 15 | endpoints: 16 | account: 127.0.0.2:8080 17 | echo: 127.0.0.3:8080 18 | -------------------------------------------------------------------------------- /services/keying/src/test/resources/simplelogger.properties: -------------------------------------------------------------------------------- 1 | org.slf4j.simpleLogger.defaultLogLevel=info 2 | org.slf4j.simpleLogger.log.micro.apps=debug 3 | -------------------------------------------------------------------------------- /services/linking/src/main/resources/config.prod.yaml: -------------------------------------------------------------------------------- 1 | certs: 2 | caCert: config/certs/ca-cert.pem 3 | clientKey: config/certs/client-key.pem 4 | clientCert: config/certs/client-cert.pem 5 | proxyKey: config/certs/proxy-key.pem 6 | proxyCert: config/certs/proxy-cert.pem 7 | upstreamKey: config/certs/upstream-key.pem 8 | upstreamCert: config/certs/upstream-cert.pem 9 | upstreamCaCert: config/certs/upstream-ca-cert.pem 10 | account: 11 | endpoint: 0.0.0.0:9444 12 | authority: www.sumo.com 13 | maxRetry: 3 14 | deadline: 3s 15 | endpoints: 16 | account: 127.0.0.2:8080 17 | echo: 127.0.0.3:8080 18 | -------------------------------------------------------------------------------- /services/linking/src/main/resources/config.yaml: -------------------------------------------------------------------------------- 1 | certs: 2 | caCert: config/certs/ca-cert.pem 3 | clientKey: config/certs/client-key.pem 4 | clientCert: config/certs/client-cert.pem 5 | proxyKey: config/certs/proxy-key.pem 6 | proxyCert: config/certs/proxy-cert.pem 7 | upstreamKey: config/certs/upstream-localhost-key.pem 8 | upstreamCert: config/certs/upstream-localhost-cert.pem 9 | upstreamCaCert: config/certs/upstream-ca-cert.pem 10 | account: 11 | endpoint: 0.0.0.0:9444 12 | authority: www.sumo.com 13 | maxRetry: 3 14 | deadline: 2s 15 | endpoints: 16 | account: 127.0.0.2:8080 17 | echo: 127.0.0.3:8080 18 | -------------------------------------------------------------------------------- /services/linking/src/main/resources/simplelogger.properties: -------------------------------------------------------------------------------- 1 | org.slf4j.simpleLogger.defaultLogLevel=info 2 | org.slf4j.simpleLogger.log.micro.apps=info 3 | -------------------------------------------------------------------------------- /services/linking/src/test/resources/config.yaml: -------------------------------------------------------------------------------- 1 | certs: 2 | caCert: config/certs/upstream-ca-cert.pem 3 | clientKey: config/certs/client-key.pem 4 | clientCert: config/certs/client-cert.pem 5 | proxyKey: config/certs/proxy-key.pem 6 | proxyCert: config/certs/proxy-cert.pem 7 | upstreamKey: config/certs/upstream-localhost-key.pem 8 | upstreamCert: config/certs/upstream-localhost-cert.pem 9 | upstreamCaCert: config/certs/upstream-ca-cert.pem 10 | account: 11 | endpoint: 0.0.0.0:5003 12 | authority: localhost 13 | maxRetry: 3 14 | deadline: 2s 15 | endpoints: 16 | account: 127.0.0.2:8080 17 | echo: 127.0.0.3:8080 18 | -------------------------------------------------------------------------------- /services/linking/src/test/resources/simplelogger.properties: -------------------------------------------------------------------------------- 1 | org.slf4j.simpleLogger.defaultLogLevel=info 2 | org.slf4j.simpleLogger.log.micro.apps=debug 3 | -------------------------------------------------------------------------------- /services/person/src/main/docker/Dockerfile.native: -------------------------------------------------------------------------------- 1 | #### 2 | # This Dockerfile is used in order to build a container that runs the Quarkus application in native (no JVM) mode 3 | # 4 | # Before building the container image run: 5 | # 6 | # ./gradlew build -Dquarkus.package.type=native 7 | # 8 | # Then, build the image with: 9 | # 10 | # docker build -f src/main/docker/Dockerfile.native -t quarkus/person-service . 11 | # 12 | # Then run the container using: 13 | # 14 | # docker run -i --rm -p 8080:8080 quarkus/person-service 15 | # 16 | ### 17 | FROM registry.access.redhat.com/ubi8/ubi-minimal:8.3 18 | WORKDIR /work/ 19 | RUN chown 1001 /work \ 20 | && chmod "g+rwX" /work \ 21 | && chown 1001:root /work 22 | COPY --chown=1001:root build/*-runner /work/application 23 | 24 | EXPOSE 8080 25 | USER 1001 26 | 27 | CMD ["./application", "-Dquarkus.http.host=0.0.0.0"] 28 | -------------------------------------------------------------------------------- /services/person/src/main/docker/Dockerfile.native-distroless: -------------------------------------------------------------------------------- 1 | #### 2 | # This Dockerfile is used in order to build a distroless container that runs the Quarkus application in native (no JVM) mode 3 | # 4 | # Before building the container image run: 5 | # 6 | # ./gradlew build -Dquarkus.package.type=native 7 | # 8 | # Then, build the image with: 9 | # 10 | # docker build -f src/main/docker/Dockerfile.native-distroless -t quarkus/person-service . 11 | # 12 | # Then run the container using: 13 | # 14 | # docker run -i --rm -p 8080:8080 quarkus/person-service 15 | # 16 | ### 17 | FROM quay.io/quarkus/quarkus-distroless-image:1.0 18 | COPY build/*-runner /application 19 | 20 | EXPOSE 8080 21 | USER nonroot 22 | 23 | CMD ["./application", "-Dquarkus.http.host=0.0.0.0"] 24 | -------------------------------------------------------------------------------- /services/person/src/main/kotlin/micro/apps/service/GreetingResource.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.service 2 | 3 | import org.eclipse.microprofile.graphql.Description 4 | import org.eclipse.microprofile.graphql.GraphQLApi 5 | import org.eclipse.microprofile.graphql.Query 6 | 7 | @GraphQLApi 8 | class GreetingResource { 9 | @Query 10 | fun hello(): String { 11 | return "hello" 12 | } 13 | 14 | @Query 15 | @Description("find all products data") 16 | fun getProducts(): List? { 17 | // you can simulate backend calls here to return the data graphql will fire only the required fields query and can be bounded to the schema. 18 | // @Mutation used for mutating data (create,update and delete operations). 19 | return java.util.List.of("test", "test1", "test2") 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /services/person/src/main/kotlin/micro/apps/service/ScoresNotAvailableException.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.service 2 | 3 | class ScoresNotAvailableException : Exception { 4 | constructor() {} 5 | constructor(string: String?) : super(string) {} 6 | constructor(string: String?, thrwbl: Throwable?) : super(string, thrwbl) {} 7 | constructor(thrwbl: Throwable?) : super(thrwbl) {} 8 | constructor(string: String?, thrwbl: Throwable?, bln: Boolean, bln1: Boolean) : super(string, thrwbl, bln, bln1) {} 9 | } 10 | -------------------------------------------------------------------------------- /services/person/src/main/resources/roles.properties: -------------------------------------------------------------------------------- 1 | sumo=admin 2 | -------------------------------------------------------------------------------- /services/person/src/main/resources/users.properties: -------------------------------------------------------------------------------- 1 | sumo=password 2 | -------------------------------------------------------------------------------- /services/person/src/native-test/kotlin/micro/apps/service/NativeGreetingResourceIT.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.service 2 | 3 | import io.quarkus.test.junit.NativeImageTest 4 | 5 | @NativeImageTest 6 | class NativeGreetingResourceIT : GreetingResourceTest() 7 | -------------------------------------------------------------------------------- /services/redis/src/main/kotlin/micro/apps/service/config/RedisConfig.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.service.config 2 | 3 | import kotlinx.serialization.ExperimentalSerializationApi 4 | import org.springframework.context.annotation.Configuration 5 | 6 | @Configuration 7 | @OptIn(ExperimentalSerializationApi::class) 8 | class RedisConfig { 9 | 10 | // @Bean 11 | // fun redisTemplate(connectionFactory: RedisConnectionFactory): RedisTemplate<*, *> { 12 | // val template: RedisTemplate<*, *> = RedisTemplate() 13 | // template.setConnectionFactory(connectionFactory) 14 | // return template 15 | // } 16 | } 17 | -------------------------------------------------------------------------------- /services/redis/src/main/kotlin/micro/apps/service/domain/account/AccountRepository.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.service.domain.account 2 | 3 | /* 4 | import kotlinx.serialization.ExperimentalSerializationApi 5 | import org.springframework.data.redis.core.RedisTemplate 6 | import org.springframework.data.repository.CrudRepository 7 | import org.springframework.stereotype.Repository 8 | import java.util.* 9 | 10 | 11 | @OptIn(ExperimentalSerializationApi::class) 12 | @Repository 13 | class AccountCustomRepository(val template: RedisTemplate) : CrudRepository { 14 | override fun findById(id: String): Optional { 15 | TODO() 16 | } 17 | } 18 | 19 | */ 20 | -------------------------------------------------------------------------------- /services/redis/src/main/kotlin/micro/apps/service/domain/account/extensions.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.service.domain.account 2 | 3 | import kotlinx.serialization.ExperimentalSerializationApi 4 | 5 | @OptIn(ExperimentalSerializationApi::class) 6 | fun PersonDto.toEntity(): PersonEntity { 7 | val addresses = this.addresses?.map { it.toEntity() }?.toSet() 8 | return PersonEntity(null, name, addresses, gender, dob, email, phone, avatar) 9 | } 10 | 11 | @OptIn(ExperimentalSerializationApi::class) 12 | fun AddressDto.toEntity() = 13 | AddressEntity(null, suite, street, city, state, code, country, location) 14 | -------------------------------------------------------------------------------- /services/redis/src/main/kotlin/micro/apps/service/domain/account/repositories.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.service.domain.account 2 | 3 | import kotlinx.serialization.ExperimentalSerializationApi 4 | import org.springframework.data.repository.PagingAndSortingRepository 5 | import org.springframework.stereotype.Repository 6 | 7 | /* 8 | * Note: Redis Repositories DO NOT work with transactions 9 | */ 10 | // interface PersonRepository : ReactiveCrudRepository { 11 | // interface PersonRepository : CoroutineSortingRepository { 12 | @OptIn(ExperimentalSerializationApi::class) 13 | @Repository 14 | interface Person1Repository : PagingAndSortingRepository 15 | 16 | @OptIn(ExperimentalSerializationApi::class) 17 | @Repository 18 | interface AddressRepository : PagingAndSortingRepository 19 | -------------------------------------------------------------------------------- /services/redis/src/main/kotlin/micro/apps/service/domain/product/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmlking/micro-apps/135c0f6b8ccfe17121a367bbfdd8024c77ea3c51/services/redis/src/main/kotlin/micro/apps/service/domain/product/.gitkeep -------------------------------------------------------------------------------- /services/redis/src/main/kotlin/micro/apps/service/models.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.service 2 | 3 | import com.redis.om.spring.annotations.Bloom 4 | import com.redis.om.spring.annotations.Indexed 5 | import com.redis.om.spring.annotations.Searchable 6 | import org.springframework.data.annotation.Id 7 | import org.springframework.data.annotation.Reference 8 | import org.springframework.data.redis.core.RedisHash 9 | 10 | @RedisHash 11 | data class Role( 12 | @Id 13 | var id: String?, 14 | @Indexed 15 | var roleName: String? 16 | ) 17 | 18 | @RedisHash 19 | data class User( 20 | @Id 21 | val id: String?, 22 | @Indexed 23 | val firstName: String, 24 | @Indexed 25 | val middleName: String?, 26 | @Searchable 27 | val lastName: String, 28 | @Indexed 29 | @Bloom(name = "bf_user_email", capacity = 100000, errorRate = 0.001) 30 | var email: String, 31 | // HINT: Reference fields should be marked as nullable.??? 32 | @Reference 33 | val role: Role? 34 | ) 35 | -------------------------------------------------------------------------------- /services/redis/src/main/resources/application-production.yml: -------------------------------------------------------------------------------- 1 | # Specify the DNS URI of your Redis cluster. 2 | spring.redis.host: redis-17814.c238.us-central1-2.gce.cloud.redislabs.com 3 | spring.redis.port: 17814 4 | # Specify the access key for your Redis cache. 5 | # spring.redis.password: 6 | -------------------------------------------------------------------------------- /services/redis/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring.application.name: redis-service 2 | 3 | 4 | # debug:true 5 | logging.level.com.redis.om.spring: DEBUG 6 | 7 | # ==== application properties ======== 8 | features: 9 | change-events: 10 | enabled: true 11 | -------------------------------------------------------------------------------- /services/spring-demo/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM openjdk:11-jre 2 | RUN mkdir -p /app/bin 3 | COPY ./target/spring-service.jar /app/bin 4 | COPY opentelemetry-javaagent-all.jar /app/bin 5 | CMD java -Dotel.exporter=jaeger \ 6 | -Dotel.exporter.jaeger.endpoint=jaeger:14250 \ 7 | -Dotel.exporter.jaeger.service.name=spring-service \ 8 | -Dapplication.home=/app/bin/ \ 9 | -Dapplication.name=OpenTelemetryAppA \ 10 | -javaagent:/app/bin/opentelemetry-javaagent-all.jar \ 11 | -jar \ 12 | /app/bin/spring-service.jar 13 | -------------------------------------------------------------------------------- /services/spring-demo/src/main/kotlin/micro/apps/service/config/OpenAPIConfig.kt: -------------------------------------------------------------------------------- 1 | // package micro.apps.service.config 2 | // 3 | // import io.swagger.v3.oas.models.OpenAPI 4 | // import io.swagger.v3.oas.models.info.Info 5 | // import org.springframework.context.annotation.Bean 6 | // import org.springframework.context.annotation.Configuration 7 | // 8 | // @Configuration 9 | // class OpenAPIConfig { 10 | // @Bean 11 | // fun springShopOpenAPI(info: Info): OpenAPI { 12 | // return OpenAPI().info(info) 13 | // } 14 | // 15 | // @Bean 16 | // fun info(): Info { 17 | // return Info() 18 | // .title("spring-boot-template") 19 | // .description("API provided by spring-boot-template") 20 | // .version("v1.0.0") // this can be ignored, the generator updates this 21 | // } 22 | // } 23 | -------------------------------------------------------------------------------- /services/spring-demo/src/main/kotlin/micro/apps/service/config/SecurityConfig.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.service.config 2 | 3 | /* 4 | @EnableWebSecurity 5 | class SecurityConfig { 6 | 7 | @Bean 8 | fun filterChain(http: HttpSecurity): SecurityFilterChain { 9 | http { 10 | authorizeRequests { 11 | authorize(anyRequest, authenticated) 12 | } 13 | formLogin { } 14 | httpBasic { } 15 | } 16 | return http.build() 17 | } 18 | 19 | @Suppress("DEPRECATION") 20 | @Bean 21 | fun userDetailsService(): UserDetailsService { 22 | val user = User.withDefaultPasswordEncoder() 23 | .username("user") 24 | .password("password") 25 | .roles("USER") 26 | .build() 27 | return InMemoryUserDetailsManager(user) 28 | } 29 | } 30 | */ 31 | -------------------------------------------------------------------------------- /services/spring-demo/src/main/kotlin/micro/apps/service/config/SwaggerConfig.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.service.config 2 | 3 | // @EnableSwagger2 4 | // @Configuration 5 | // class SwaggerConfig { 6 | // 7 | // @Bean 8 | // fun configureSwagger() = Docket(DocumentationType.SWAGGER_2) 9 | // .select() 10 | // .apis(RequestHandlerSelectors.any()) 11 | // .paths(regex("/v1/.*")) 12 | // .build() 13 | // } 14 | -------------------------------------------------------------------------------- /services/spring-demo/src/main/resources/ValidationMessages.properties: -------------------------------------------------------------------------------- 1 | exact.size=size must be {max} 2 | only.numbers=must be numbers only 3 | -------------------------------------------------------------------------------- /services/spring-demo/src/main/resources/application-production.yml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /services/spring-demo/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring.application.name: entity-service 2 | 3 | spring.rsocket.server.transport: websocket 4 | spring.rsocket.server.mapping-path: /rsocket 5 | 6 | # ==== application properties ======== 7 | #features: 8 | # change-events: 9 | # enabled: true 10 | 11 | # =============== grpc =============== 12 | grpc: 13 | port: 6565 14 | enableReflection: true 15 | 16 | # =============== server =============== 17 | server: 18 | shutdown: graceful # also set `timeout-per-shutdown-phase` 19 | 20 | # =============== management =============== 21 | management.endpoints.web.exposure.include: prometheus,health,info,metrics 22 | 23 | # =============== spring =============== 24 | spring: 25 | 26 | lifecycle: 27 | timeout-per-shutdown-phase: "10s" 28 | -------------------------------------------------------------------------------- /services/spring-demo/src/main/resources/banner.txt: -------------------------------------------------------------------------------- 1 | _____ _ _ 2 | / ___| | | | | 3 | \ `--. _ _ _ __ ___ __ _ _ __ | |_ | |__ 4 | `--. \| | | || '_ ` _ \ / _` || '_ \ | __|| '_ \ 5 | /\__/ /| |_| || | | | | || (_| || | | || |_ | | | | 6 | \____/ \__,_||_| |_| |_| \__,_||_| |_| \__||_| |_| 7 | -------------------------------------------------------------------------------- /services/spring-demo/src/main/resources/data.sql: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmlking/micro-apps/135c0f6b8ccfe17121a367bbfdd8024c77ea3c51/services/spring-demo/src/main/resources/data.sql -------------------------------------------------------------------------------- /services/spring-demo/src/main/resources/messages.properties: -------------------------------------------------------------------------------- 1 | # https://github.com/Diones/kotlin-sample/tree/master/card/src/main/resources 2 | 001=Contact system admin. 3 | 002=Field ''{0}'' has an invalid value - {1}. 4 | 003=Missing required parameter ''{0}'' - Type ''{1}''. 5 | 004=Request method ''{0}'' not supported. 6 | 100=Card not found 7 | 101=User not found 8 | -------------------------------------------------------------------------------- /services/spring-demo/src/main/resources/schema.sql: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmlking/micro-apps/135c0f6b8ccfe17121a367bbfdd8024c77ea3c51/services/spring-demo/src/main/resources/schema.sql -------------------------------------------------------------------------------- /services/spring-demo/src/test/kotlin/micro/apps/service/EntityApplicationTest.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.service 2 | 3 | import io.kotest.core.spec.style.FunSpec 4 | import io.kotest.matchers.nulls.shouldNotBeNull 5 | import org.springframework.boot.test.context.SpringBootTest 6 | import org.springframework.core.env.Environment 7 | 8 | @SpringBootTest 9 | class EntityApplicationTest(private val environment: Environment) : FunSpec({ 10 | test("application starts") { 11 | environment.shouldNotBeNull() 12 | } 13 | }) 14 | -------------------------------------------------------------------------------- /services/spring-demo/src/test/kotlin/micro/apps/service/ProjectConfig.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.service 2 | 3 | import io.kotest.core.config.AbstractProjectConfig 4 | import io.kotest.extensions.spring.SpringExtension 5 | 6 | class ProjectConfig : AbstractProjectConfig() { 7 | override fun extensions() = listOf(SpringExtension) 8 | } 9 | -------------------------------------------------------------------------------- /services/spring-graphql-jpa/src/main/kotlin/micro/apps/service/Application.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.service 2 | 3 | import org.springframework.boot.autoconfigure.SpringBootApplication 4 | import org.springframework.boot.context.properties.ConfigurationPropertiesScan 5 | import org.springframework.boot.runApplication 6 | 7 | @ConfigurationPropertiesScan 8 | @SpringBootApplication 9 | class DemoApplication 10 | 11 | fun main(args: Array) { 12 | runApplication(*args) 13 | } 14 | -------------------------------------------------------------------------------- /services/spring-graphql-jpa/src/main/kotlin/micro/apps/service/config/Authorities.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.service.config 2 | 3 | object Authorities { 4 | const val SCOPE_ACTUATOR = "SCOPE_ACTUATOR" 5 | const val SCOPE_GRAPHQL = "SCOPE_GRAPHQL" 6 | const val SCOPE_GRAPHIQL = "SCOPE_GRAPHIQL" 7 | const val SCOPE_H2 = "SCOPE_H2" 8 | 9 | const val READ_AUTHORITY = "READ_AUTHORITY" 10 | const val WRITE_AUTHORITY = "WRITE_AUTHORITY" 11 | const val UPDATE_AUTHORITY = "UPDATE_AUTHORITY" 12 | const val DELETE_AUTHORITY = "DELETE_AUTHORITY" 13 | } 14 | 15 | object Roles { 16 | const val ROLE_VIEWER = "SCOPE_viewer" 17 | const val ROLE_EDITOR = "SCOPE_editor" 18 | const val ROLE_MODERATOR = "SCOPE_moderator" 19 | const val ROLE_SUPERVISOR = "SCOPE_supervisor" 20 | } 21 | -------------------------------------------------------------------------------- /services/spring-graphql-jpa/src/main/kotlin/micro/apps/service/config/UsersProperties.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.service.config 2 | 3 | import org.springframework.boot.context.properties.ConfigurationProperties 4 | 5 | @ConfigurationProperties("security.users") 6 | data class UsersProperties( 7 | val basicAuth: List 8 | ) { 9 | data class BasicAuthUser( 10 | val username: String, 11 | val password: String, 12 | val authorities: Set 13 | ) 14 | } 15 | -------------------------------------------------------------------------------- /services/spring-graphql-jpa/src/main/kotlin/micro/apps/service/exception/MessageConstants.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.service.exception 2 | 3 | const val USER_NOT_FOUND_MSG_CODE = "error.user.not.found.message" 4 | const val ROLE_NAME_NOT_FOUND_MSG_CODE = "error.roleName.not.found.message" 5 | const val EMAIL_ALREADY_EXISTS_MSG_CODE = "error.email.already.exists.message" 6 | const val USERNAME_ALREADY_EXISTS_MSG_CODE = "error.username.already.exists.message" 7 | 8 | const val POST_NOT_FOUND_MSG_CODE = "error.post.not.found.message" 9 | 10 | const val RECAPTCHA_INVALID_MSG_CODE = "error.recaptcha.invalid.message" 11 | -------------------------------------------------------------------------------- /services/spring-graphql-jpa/src/main/kotlin/micro/apps/service/exception/exceptions.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.service.exception 2 | 3 | /** 4 | * Project specific Exceptions 5 | * See `:libs:graphql` for shared Exceptions 6 | */ 7 | class ItemBizException(message: String?, args: Array? = null) : GraphqlException(message, args) 8 | -------------------------------------------------------------------------------- /services/spring-graphql-jpa/src/main/kotlin/micro/apps/service/util/Extensions.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.service.util 2 | 3 | import org.springframework.security.core.context.SecurityContext 4 | import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken 5 | import java.security.Principal 6 | 7 | fun SecurityContext.jwtAuthentication(): JwtAuthenticationToken { 8 | return authentication as JwtAuthenticationToken 9 | } 10 | 11 | fun Principal.jwtAuthentication(): JwtAuthenticationToken? { 12 | return this as? JwtAuthenticationToken 13 | } 14 | 15 | fun JwtAuthenticationToken.tokenValue(): String { 16 | return this.token.tokenValue 17 | } 18 | -------------------------------------------------------------------------------- /services/spring-graphql-jpa/src/main/resources/application-local.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | h2: 3 | console: 4 | enabled: true -------------------------------------------------------------------------------- /services/spring-graphql-jpa/src/main/resources/application-production.yml: -------------------------------------------------------------------------------- 1 | debug: false 2 | logging: 3 | level: 4 | root: INFO 5 | org.springframework.security: DEBUG 6 | # ==================== spring ============================== 7 | spring: 8 | graphql: 9 | schema: 10 | printer: 11 | enabled: true 12 | graphiql: 13 | enabled: true 14 | jpa: 15 | database-platform: org.hibernate.dialect.PostgreSQL10Dialect 16 | show-sql: true 17 | generate-ddl: false 18 | hibernate: 19 | ddl-auto: validate 20 | properties: 21 | hibernate.temp.use_jdbc_metadata_defaults: false 22 | -------------------------------------------------------------------------------- /services/spring-graphql-jpa/src/main/resources/application-test.yml: -------------------------------------------------------------------------------- 1 | debug: false 2 | # ==================== spring ============================== 3 | spring: 4 | autoconfigure: 5 | exclude: 6 | - org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration 7 | - org.springframework.boot.actuate.autoconfigure.security.reactive.ReactiveManagementWebSecurityAutoConfiguration 8 | -------------------------------------------------------------------------------- /services/spring-graphql-jpa/src/main/resources/db/migration/V1__My_First_Migration.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE item ( 2 | id SERIAL NOT NULL PRIMARY KEY, 3 | name VARCHAR(255) NOT NULL, 4 | description TEXT 5 | ); 6 | -------------------------------------------------------------------------------- /services/spring-graphql-jpa/src/main/resources/db/test-data/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmlking/micro-apps/135c0f6b8ccfe17121a367bbfdd8024c77ea3c51/services/spring-graphql-jpa/src/main/resources/db/test-data/.gitkeep -------------------------------------------------------------------------------- /services/spring-graphql-jpa/src/main/resources/graphql/item.graphqls: -------------------------------------------------------------------------------- 1 | extend type Query { 2 | items(id: [ID], name: String): [Item] 3 | item(id: ID!): Item 4 | listItems: [Item] 5 | findAll(offset: Int = 0, limit: Int = 10, orderBy: String = "name"): [Item] 6 | } 7 | 8 | extend type Mutation { 9 | addItem(input: ItemInput!): Item 10 | deleteItem(id: ID!): Item 11 | } 12 | 13 | type Item { 14 | id: ID! 15 | name: String! 16 | description: String 17 | } 18 | 19 | input ItemInput { 20 | name: String! @NotBlank @Size(min: 4, max: 50) 21 | description: String 22 | } 23 | -------------------------------------------------------------------------------- /services/spring-graphql-jpa/src/main/resources/graphql/message.graphqls: -------------------------------------------------------------------------------- 1 | extend type Query { 2 | hello: Message 3 | } 4 | 5 | extend type Mutation { 6 | addMessage(input: AddMessageInput!): Message! 7 | } 8 | 9 | extend type Subscription { 10 | messages: Message! 11 | } 12 | 13 | type Message { 14 | id: ID!, 15 | content: String! 16 | } 17 | 18 | input AddMessageInput { 19 | content: String! @NotBlank @Size(min: 4, max: 1000) 20 | } 21 | -------------------------------------------------------------------------------- /services/spring-graphql-jpa/src/main/resources/i18n/messages.properties: -------------------------------------------------------------------------------- 1 | post.title=New Post: {0} 2 | error.resource.not.found.message={0} with {1} {2} was not found 3 | error.constraint.violation.message=Invalid Input 4 | error.user.not.found.message=User with id {0} was not found 5 | error.roleName.not.found.message=Role with name {0} was not found 6 | error.post.not.found.message=Post with id {0} was not found 7 | error.username.already.exists.message=Username is already in use! 8 | error.email.already.exists.message=Email is already in use! 9 | error.recaptcha.invalid.message=reCaptcha validation failed 10 | -------------------------------------------------------------------------------- /services/spring-graphql-jpa/src/main/resources/i18n/messages_tr.properties: -------------------------------------------------------------------------------- 1 | post.title=Yeni \u0130leti: {0} 2 | error.resource.not.found.message={0} {1} {2} bulunamad\u0131 3 | error.constraint.violation.message=Ge\u00E7ersiz Input 4 | error.user.not.found.message=Kullan\u0131c\u0131 id {0} bulunamad\u0131 5 | error.post.not.found.message=\u0130leti id {0} bulunamad\u0131 6 | error.roleName.not.found.message=Role ad\u0131 {0} bulunamad\u0131 7 | error.username.already.exists.message=Kullan\u0131c\u0131 ad\u0131 zaten kullan\u0131l\u0131yor! 8 | error.email.already.exists.message=Mail zaten kullan\u0131l\u0131yor! 9 | error.recaptcha.invalid.message=reCaptcha do\u011Frulama ba\u015Far\u0131s\u0131z 10 | -------------------------------------------------------------------------------- /services/spring-graphql-jpa/src/test/kotlin/micro/apps/service/DemoApplicationTests.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.service 2 | 3 | import io.kotest.matchers.nulls.shouldNotBeNull 4 | import org.junit.jupiter.api.Test 5 | import org.springframework.beans.factory.annotation.Autowired 6 | import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient 7 | import org.springframework.boot.test.context.SpringBootTest 8 | import org.springframework.test.web.reactive.server.WebTestClient 9 | 10 | @SpringBootTest 11 | @AutoConfigureWebTestClient 12 | class DemoApplicationTests(@Autowired private val webTestClient: WebTestClient) { 13 | 14 | @Test 15 | fun contextLoads() { 16 | // when 17 | val schema = 18 | webTestClient 19 | .get() 20 | .uri("/gql") 21 | .exchange() 22 | .returnResult(String::class.java) 23 | .responseBody 24 | .reduce { a, b -> a + "\n" + b } 25 | .block() 26 | 27 | // then 28 | schema.shouldNotBeNull() 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /services/spring-graphql-jpa/src/test/resources/config/application.yml: -------------------------------------------------------------------------------- 1 | # this config override src/main/resources/application.yml 2 | # and combined config is used by tests. 3 | # If we also set `spring.profiles.active=test` env for gradle test task, 4 | # src/main/resources/application-test.yml config also loaded and mixed. 5 | # beans tagged with @Profile("!test") are ignored. 6 | debug: false 7 | # ==================== spring ============================== 8 | spring: 9 | autoconfigure: 10 | exclude: 11 | - org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration 12 | - org.springframework.boot.actuate.autoconfigure.security.reactive.ReactiveManagementWebSecurityAutoConfiguration 13 | # ==================== application properties ============= 14 | command: 15 | line: 16 | runner: 17 | enabled: false 18 | -------------------------------------------------------------------------------- /services/spring-graphql-jpa/src/test/resources/graphql-test/MUTATION.AddItem.gql: -------------------------------------------------------------------------------- 1 | mutation AddItem($input: ItemInput!) { 2 | addItem(input: $input) { 3 | id, 4 | name, 5 | description 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /services/spring-graphql-jpa/src/test/resources/graphql-test/QUERY.ListItems.gql: -------------------------------------------------------------------------------- 1 | query ListItems { 2 | listItems { 3 | id, 4 | name, 5 | description 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /services/spring-graphql-r2dbc/src/main/kotlin/micro/apps/service/Application.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.service 2 | 3 | import org.springframework.boot.autoconfigure.SpringBootApplication 4 | import org.springframework.boot.context.properties.ConfigurationPropertiesScan 5 | import org.springframework.boot.runApplication 6 | 7 | @ConfigurationPropertiesScan 8 | @SpringBootApplication 9 | class DemoApplication 10 | 11 | fun main(args: Array) { 12 | runApplication(*args) 13 | } 14 | -------------------------------------------------------------------------------- /services/spring-graphql-r2dbc/src/main/kotlin/micro/apps/service/config/AppNativeHints.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.service.config 2 | 3 | // https://github.com/susimsek/spring-boot-native-reactive-graphql-api-example/blob/master/src/main/kotlin/io/github/susimsek/springnativegraphqlexample/config/AppNativeHints.kt 4 | class AppNativeHints 5 | -------------------------------------------------------------------------------- /services/spring-graphql-r2dbc/src/main/kotlin/micro/apps/service/config/Authorities.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.service.config 2 | 3 | object Authorities { 4 | const val SCOPE_ACTUATOR = "SCOPE_ACTUATOR" 5 | const val SCOPE_GRAPHQL = "SCOPE_GRAPHQL" 6 | const val SCOPE_GRAPHIQL = "SCOPE_GRAPHIQL" 7 | const val SCOPE_H2 = "SCOPE_H2" 8 | 9 | const val READ_AUTHORITY = "READ_AUTHORITY" 10 | const val WRITE_AUTHORITY = "WRITE_AUTHORITY" 11 | const val UPDATE_AUTHORITY = "UPDATE_AUTHORITY" 12 | const val DELETE_AUTHORITY = "DELETE_AUTHORITY" 13 | } 14 | 15 | object Roles { 16 | const val ROLE_VIEWER = "SCOPE_viewer" 17 | const val ROLE_EDITOR = "SCOPE_editor" 18 | const val ROLE_MODERATOR = "SCOPE_moderator" 19 | const val ROLE_SUPERVISOR = "SCOPE_supervisor" 20 | } 21 | -------------------------------------------------------------------------------- /services/spring-graphql-r2dbc/src/main/kotlin/micro/apps/service/config/UsersProperties.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.service.config 2 | 3 | import org.springframework.boot.context.properties.ConfigurationProperties 4 | 5 | @ConfigurationProperties("security.users") 6 | data class UsersProperties( 7 | val basicAuth: List 8 | ) { 9 | data class BasicAuthUser( 10 | val username: String, 11 | val password: String, 12 | val authorities: Set 13 | ) 14 | } 15 | -------------------------------------------------------------------------------- /services/spring-graphql-r2dbc/src/main/kotlin/micro/apps/service/domain/book/AuthorRepository.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.service.domain.book 2 | 3 | import org.springframework.data.repository.kotlin.CoroutineCrudRepository 4 | import org.springframework.data.repository.kotlin.CoroutineSortingRepository 5 | import org.springframework.graphql.data.GraphQlRepository 6 | import java.util.UUID 7 | 8 | @GraphQlRepository 9 | interface AuthorRepository : CoroutineCrudRepository, CoroutineSortingRepository { 10 | suspend fun findAuthorByBookId(id: UUID): Author 11 | } 12 | -------------------------------------------------------------------------------- /services/spring-graphql-r2dbc/src/main/kotlin/micro/apps/service/domain/book/BookRepository.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.service.domain.book 2 | 3 | import kotlinx.coroutines.flow.Flow 4 | import org.springframework.data.r2dbc.repository.Query 5 | import org.springframework.data.repository.kotlin.CoroutineCrudRepository 6 | import org.springframework.data.repository.kotlin.CoroutineSortingRepository 7 | import org.springframework.graphql.data.GraphQlRepository 8 | import java.util.UUID 9 | 10 | @GraphQlRepository 11 | interface BookRepository : CoroutineCrudRepository, CoroutineSortingRepository { 12 | @Query("SELECT * FROM books WHERE name = @name") 13 | fun findAllByName(name: String): Flow 14 | } 15 | -------------------------------------------------------------------------------- /services/spring-graphql-r2dbc/src/main/kotlin/micro/apps/service/exception/MessageConstants.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.service.exception 2 | 3 | const val USER_NOT_FOUND_MSG_CODE = "error.user.not.found.message" 4 | const val ROLE_NAME_NOT_FOUND_MSG_CODE = "error.roleName.not.found.message" 5 | const val EMAIL_ALREADY_EXISTS_MSG_CODE = "error.email.already.exists.message" 6 | const val USERNAME_ALREADY_EXISTS_MSG_CODE = "error.username.already.exists.message" 7 | 8 | const val POST_NOT_FOUND_MSG_CODE = "error.post.not.found.message" 9 | 10 | const val RECAPTCHA_INVALID_MSG_CODE = "error.recaptcha.invalid.message" 11 | -------------------------------------------------------------------------------- /services/spring-graphql-r2dbc/src/main/kotlin/micro/apps/service/exception/exceptions.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.service.exception 2 | 3 | /** 4 | * Project specific Exceptions 5 | * See `:libs:graphql` for shared Exceptions 6 | */ 7 | class ItemBizException(message: String?, args: Array? = null) : GraphqlException(message, args) 8 | -------------------------------------------------------------------------------- /services/spring-graphql-r2dbc/src/main/kotlin/micro/apps/service/util/Extensions.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.service.util 2 | 3 | import org.springframework.security.core.context.SecurityContext 4 | import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken 5 | import java.security.Principal 6 | 7 | fun SecurityContext.jwtAuthentication(): JwtAuthenticationToken { 8 | return authentication as JwtAuthenticationToken 9 | } 10 | 11 | fun Principal.jwtAuthentication(): JwtAuthenticationToken? { 12 | return this as? JwtAuthenticationToken 13 | } 14 | 15 | fun JwtAuthenticationToken.tokenValue(): String { 16 | return this.token.tokenValue 17 | } 18 | -------------------------------------------------------------------------------- /services/spring-graphql-r2dbc/src/main/resources/application-local.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | h2: 3 | console: 4 | enabled: true -------------------------------------------------------------------------------- /services/spring-graphql-r2dbc/src/main/resources/application-production.yml: -------------------------------------------------------------------------------- 1 | debug: false 2 | logging: 3 | level: 4 | root: INFO 5 | org.springframework.security: DEBUG 6 | # ==================== spring ============================== 7 | spring: 8 | graphql: 9 | schema: 10 | printer: 11 | enabled: true 12 | graphiql: 13 | enabled: true 14 | -------------------------------------------------------------------------------- /services/spring-graphql-r2dbc/src/main/resources/application-test.yml: -------------------------------------------------------------------------------- 1 | debug: false 2 | # ==================== spring ============================== 3 | spring: 4 | autoconfigure: 5 | exclude: 6 | - org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration 7 | - org.springframework.boot.actuate.autoconfigure.security.reactive.ReactiveManagementWebSecurityAutoConfiguration 8 | r2dbc: 9 | url: r2dbc:h2:file://././build/database/testdb;MODE=PostgreSQL;DATABASE_TO_LOWER=TRUE;DEFAULT_NULL_ORDERING=HIGH;AUTO_SERVER=TRUE 10 | name: testdb 11 | username: sa 12 | password: Passw@rd 13 | # ==================== application properties ============= 14 | application: 15 | runner: 16 | enabled: false 17 | -------------------------------------------------------------------------------- /services/spring-graphql-r2dbc/src/main/resources/db/migration/common/V1_0_0__common_init.sql: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmlking/micro-apps/135c0f6b8ccfe17121a367bbfdd8024c77ea3c51/services/spring-graphql-r2dbc/src/main/resources/db/migration/common/V1_0_0__common_init.sql -------------------------------------------------------------------------------- /services/spring-graphql-r2dbc/src/main/resources/db/migration/h2/V1_0_1__create_table_book.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE IF NOT EXISTS books ( 2 | id UUID NOT NULL DEFAULT random_uuid() PRIMARY KEY, 3 | title VARCHAR(255) NOT NULL, 4 | pages DECIMAL(10), 5 | -- category ENUM('HORROR', 'COMEDY', 'FANTASY') NOT NULL, 6 | category varchar(255) check (category in ('HORROR', 'COMEDY', 'FANTASY')), 7 | created_at TIMESTAMP WITH TIME ZONE NOT NULL, 8 | created_by VARCHAR(255) NOT NULL, 9 | updated_at TIMESTAMP WITH TIME ZONE, 10 | updated_by VARCHAR(255), 11 | version int8 not null 12 | ); 13 | 14 | CREATE TABLE IF NOT EXISTS authors ( 15 | id UUID NOT NULL DEFAULT random_uuid() PRIMARY KEY, 16 | name VARCHAR(255) NOT NULL, 17 | age DECIMAL(10), 18 | version int8 not null, 19 | book_id UUID not null, 20 | foreign key (book_id) references books(id) 21 | ); 22 | -------------------------------------------------------------------------------- /services/spring-graphql-r2dbc/src/main/resources/db/migration/h2/V1_1_0__create_table_item.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE item ( 2 | id SERIAL NOT NULL PRIMARY KEY, 3 | name VARCHAR(255) NOT NULL, 4 | description TEXT 5 | ); 6 | -------------------------------------------------------------------------------- /services/spring-graphql-r2dbc/src/main/resources/db/migration/postgresql/V1_0_1__create_table_book.sql: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmlking/micro-apps/135c0f6b8ccfe17121a367bbfdd8024c77ea3c51/services/spring-graphql-r2dbc/src/main/resources/db/migration/postgresql/V1_0_1__create_table_book.sql -------------------------------------------------------------------------------- /services/spring-graphql-r2dbc/src/main/resources/db/migration/sqlserver/V1_0_1__create_table_book.sql: -------------------------------------------------------------------------------- 1 | -- CREATE DATABASE mytestdb 2 | -- GO 3 | -- USE mytestdb 4 | -- GO 5 | 6 | 7 | CREATE TABLE books ( 8 | Id UNIQUEIDENTIFIER NOT NULL PRIMARY KEY DEFAULT NEWID(), 9 | title VARCHAR(255) NOT NULL, 10 | pages DECIMAL(10), 11 | -- category ENUM('HORROR', 'COMEDY', 'FANTASY') NOT NULL, 12 | category varchar(255) check (category in ('HORROR', 'COMEDY', 'FANTASY')), 13 | created_at datetimeoffset NOT NULL, 14 | created_by VARCHAR(255) NOT NULL, 15 | updated_at datetimeoffset, 16 | updated_by VARCHAR(255), 17 | version int not null 18 | ); 19 | 20 | CREATE TABLE authors ( 21 | Id UNIQUEIDENTIFIER NOT NULL PRIMARY KEY DEFAULT NEWID(), 22 | name VARCHAR(255) NOT NULL, 23 | age DECIMAL(10), 24 | version int not null, 25 | book_id UNIQUEIDENTIFIER not null, 26 | foreign key (book_id) references books(id) 27 | ); 28 | -------------------------------------------------------------------------------- /services/spring-graphql-r2dbc/src/main/resources/graphql/book.graphqls: -------------------------------------------------------------------------------- 1 | extend type Query { 2 | bookById(id: UUID!): Book 3 | bookByTitle(title: String!): Book 4 | books : [Book!] 5 | } 6 | 7 | extend type Mutation { 8 | createBook(input: CreateBookInput!): Book 9 | # deleteBook(id: ID!): Book 10 | } 11 | 12 | extend type Subscription { 13 | bookStream(category: Category): Book! 14 | } 15 | 16 | 17 | type Book { 18 | id: UUID! 19 | title: String! 20 | pages: Int! 21 | category: Category! 22 | author: Author 23 | createdAt: LocalDateTime 24 | createdBy: String 25 | updatedAt: LocalDateTime 26 | updatedBy: String 27 | } 28 | 29 | type Author { 30 | id: UUID! 31 | name: String! 32 | age: Int 33 | } 34 | 35 | input CreateBookInput { 36 | title: String! @NotBlank @Size(min: 4, max: 50) 37 | pages: Int 38 | category: Category! 39 | author: String! @NotBlank @Size(min: 4, max: 50) 40 | } 41 | 42 | enum Category { 43 | HORROR 44 | COMEDY 45 | FANTASY 46 | } 47 | -------------------------------------------------------------------------------- /services/spring-graphql-r2dbc/src/main/resources/graphql/item.graphqls: -------------------------------------------------------------------------------- 1 | extend type Query { 2 | items(id: [ID], name: String): [Item] 3 | item(id: ID!): Item 4 | listItems: [Item] 5 | findAll(offset: Int = 0, limit: Int = 10, orderBy: String = "name"): [Item] 6 | } 7 | 8 | extend type Mutation { 9 | addItem(input: ItemInput!): Item 10 | deleteItem(id: ID!): Item 11 | } 12 | 13 | type Item { 14 | id: ID! 15 | name: String! 16 | description: String 17 | } 18 | 19 | input ItemInput { 20 | name: String! @NotBlank @Size(min: 4, max: 50) 21 | description: String 22 | } 23 | -------------------------------------------------------------------------------- /services/spring-graphql-r2dbc/src/main/resources/graphql/message.graphqls: -------------------------------------------------------------------------------- 1 | extend type Query { 2 | hello: Message 3 | } 4 | 5 | extend type Mutation { 6 | addMessage(input: AddMessageInput!): Message! 7 | } 8 | 9 | extend type Subscription { 10 | messages: Message! 11 | } 12 | 13 | type Message { 14 | id: ID!, 15 | content: String! 16 | } 17 | 18 | input AddMessageInput { 19 | content: String! @NotBlank @Size(min: 4, max: 1000) 20 | } 21 | -------------------------------------------------------------------------------- /services/spring-graphql-r2dbc/src/main/resources/i18n/messages.properties: -------------------------------------------------------------------------------- 1 | post.title=New Post: {0} 2 | error.resource.not.found.message={0} with {1} {2} was not found 3 | error.constraint.violation.message=Invalid Input 4 | error.user.not.found.message=User with id {0} was not found 5 | error.roleName.not.found.message=Role with name {0} was not found 6 | error.post.not.found.message=Post with id {0} was not found 7 | error.username.already.exists.message=Username is already in use! 8 | error.email.already.exists.message=Email is already in use! 9 | error.recaptcha.invalid.message=reCaptcha validation failed 10 | -------------------------------------------------------------------------------- /services/spring-graphql-r2dbc/src/main/resources/i18n/messages_tr.properties: -------------------------------------------------------------------------------- 1 | post.title=Yeni \u0130leti: {0} 2 | error.resource.not.found.message={0} {1} {2} bulunamad\u0131 3 | error.constraint.violation.message=Ge\u00E7ersiz Input 4 | error.user.not.found.message=Kullan\u0131c\u0131 id {0} bulunamad\u0131 5 | error.post.not.found.message=\u0130leti id {0} bulunamad\u0131 6 | error.roleName.not.found.message=Role ad\u0131 {0} bulunamad\u0131 7 | error.username.already.exists.message=Kullan\u0131c\u0131 ad\u0131 zaten kullan\u0131l\u0131yor! 8 | error.email.already.exists.message=Mail zaten kullan\u0131l\u0131yor! 9 | error.recaptcha.invalid.message=reCaptcha do\u011Frulama ba\u015Far\u0131s\u0131z 10 | -------------------------------------------------------------------------------- /services/spring-graphql-r2dbc/src/test/kotlin/micro/apps/service/DemoApplicationTests.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.service 2 | 3 | import io.kotest.matchers.nulls.shouldNotBeNull 4 | import org.junit.jupiter.api.Test 5 | import org.springframework.beans.factory.annotation.Autowired 6 | import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient 7 | import org.springframework.boot.test.context.SpringBootTest 8 | import org.springframework.test.web.reactive.server.WebTestClient 9 | 10 | @SpringBootTest 11 | @AutoConfigureWebTestClient 12 | class DemoApplicationTests(@Autowired private val webTestClient: WebTestClient) { 13 | 14 | @Test 15 | fun contextLoads() { 16 | // when 17 | val schema = 18 | webTestClient 19 | .get() 20 | .uri("/gql") 21 | .exchange() 22 | .returnResult(String::class.java) 23 | .responseBody 24 | .reduce { a, b -> a + "\n" + b } 25 | .block() 26 | 27 | // then 28 | schema.shouldNotBeNull() 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /services/spring-graphql-r2dbc/src/test/kotlin/micro/apps/service/domain/book/BookIntegrationTest.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.service.domain.book 2 | 3 | import io.kotest.core.spec.style.FunSpec 4 | import micro.apps.test.E2E 5 | import mu.KotlinLogging 6 | import org.flywaydb.core.Flyway 7 | import org.springframework.boot.test.context.SpringBootTest 8 | 9 | /** 10 | * TODO https://maciejwalkowiak.com/blog/spring-boot-flyway-clear-database-integration-tests/ 11 | */ 12 | private val logger = KotlinLogging.logger {} 13 | 14 | @SpringBootTest() 15 | internal class BookIntegrationTest( 16 | private val bookService: BookService, 17 | private val flyway: Flyway 18 | ) : FunSpec({ 19 | 20 | lateinit var input: CreateBookInput 21 | 22 | beforeTest { 23 | logger.atDebug().log("before each test...") 24 | flyway.clean() 25 | flyway.migrate() 26 | } 27 | 28 | test("list").config(enabled = true, tags = setOf(E2E)) { 29 | } 30 | }) 31 | -------------------------------------------------------------------------------- /services/spring-graphql-r2dbc/src/test/resources/config/application.yml: -------------------------------------------------------------------------------- 1 | # this config override src/main/resources/application.yml 2 | # and combined config is used by tests. 3 | # If we also set `spring.profiles.active=test` env for gradle test task, 4 | # src/main/resources/application-test.yml config also loaded and mixed. 5 | # beans tagged with @Profile("!test") are ignored. 6 | # ==================== spring ============================== 7 | spring: 8 | profiles: 9 | active: test 10 | -------------------------------------------------------------------------------- /services/spring-graphql-r2dbc/src/test/resources/db/testdata/afterMigrate.sql: -------------------------------------------------------------------------------- 1 | ---- START 2 | -- INSERT INTO item (name, description) values ('sumo', 'demo') ON CONFLICT DO NOTHING; 3 | INSERT INTO item (name, description) values ('sumo', 'demo'); 4 | INSERT INTO item (name, description) values ('simple', 'basic') 5 | ----END 6 | -------------------------------------------------------------------------------- /services/spring-graphql-r2dbc/src/test/resources/graphql-test/MUTATION.AddItem.gql: -------------------------------------------------------------------------------- 1 | mutation AddItem($input: ItemInput!) { 2 | addItem(input: $input) { 3 | id, 4 | name, 5 | description 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /services/spring-graphql-r2dbc/src/test/resources/graphql-test/MUTATION.CreateBook.gql: -------------------------------------------------------------------------------- 1 | mutation CreateBook($input: CreateBookInput!) { 2 | createBook(input: $input) { 3 | id, 4 | title, 5 | category, 6 | createdAt, 7 | createdBy, 8 | updatedAt, 9 | updatedBy 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /services/spring-graphql-r2dbc/src/test/resources/graphql-test/QUERY.ListItems.gql: -------------------------------------------------------------------------------- 1 | query ListItems { 2 | listItems { 3 | id, 4 | name, 5 | description 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /services/spring-graphql-redis/src/main/kotlin/micro/apps/service/Application.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.service 2 | 3 | import com.redis.om.spring.annotations.EnableRedisEnhancedRepositories 4 | import org.springframework.boot.autoconfigure.SpringBootApplication 5 | import org.springframework.boot.context.properties.ConfigurationPropertiesScan 6 | import org.springframework.boot.runApplication 7 | 8 | @ConfigurationPropertiesScan 9 | @SpringBootApplication 10 | @EnableRedisEnhancedRepositories(basePackages = ["micro.apps.service"], considerNestedRepositories = false) // HINT without basePackages, index will not be created 11 | class RomsHashesApplication 12 | 13 | fun main(args: Array) { 14 | runApplication(*args) 15 | } 16 | -------------------------------------------------------------------------------- /services/spring-graphql-redis/src/main/kotlin/micro/apps/service/config/RedisConfig.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.service.config 2 | 3 | import kotlinx.serialization.ExperimentalSerializationApi 4 | import org.springframework.context.annotation.Configuration 5 | 6 | @Configuration 7 | @OptIn(ExperimentalSerializationApi::class) 8 | class RedisConfig { 9 | 10 | // @Bean 11 | // fun redisTemplate(connectionFactory: RedisConnectionFactory): RedisTemplate<*, *> { 12 | // val template: RedisTemplate<*, *> = RedisTemplate() 13 | // template.setConnectionFactory(connectionFactory) 14 | // return template 15 | // } 16 | } 17 | -------------------------------------------------------------------------------- /services/spring-graphql-redis/src/main/kotlin/micro/apps/service/domain/account/extensions.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.service.domain.account 2 | 3 | import kotlinx.serialization.ExperimentalSerializationApi 4 | 5 | @OptIn(ExperimentalSerializationApi::class) 6 | fun PersonDto.toEntity(): PersonEntity { 7 | val addresses = this.addresses?.map { it.toEntity() }?.toSet() 8 | return PersonEntity(null, name, addresses, gender, dob, email, phone, avatar) 9 | } 10 | 11 | @OptIn(ExperimentalSerializationApi::class) 12 | fun AddressDto.toEntity() = 13 | AddressEntity(null, suite, street, city, state, code, country, location) 14 | -------------------------------------------------------------------------------- /services/spring-graphql-redis/src/main/kotlin/micro/apps/service/domain/account/repositories.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.service.domain.account 2 | 3 | import kotlinx.serialization.ExperimentalSerializationApi 4 | import org.springframework.data.repository.CrudRepository 5 | import org.springframework.data.repository.PagingAndSortingRepository 6 | import org.springframework.stereotype.Repository 7 | 8 | /* 9 | * Note: Redis Repositories DO NOT work with transactions 10 | */ 11 | // interface PersonRepository : ReactiveCrudRepository { 12 | // interface PersonRepository : CoroutineSortingRepository { 13 | @OptIn(ExperimentalSerializationApi::class) 14 | @Repository 15 | interface Person1Repository : PagingAndSortingRepository, CrudRepository 16 | 17 | @OptIn(ExperimentalSerializationApi::class) 18 | @Repository 19 | interface AddressRepository : PagingAndSortingRepository, CrudRepository 20 | -------------------------------------------------------------------------------- /services/spring-graphql-redis/src/main/kotlin/micro/apps/service/domain/product/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmlking/micro-apps/135c0f6b8ccfe17121a367bbfdd8024c77ea3c51/services/spring-graphql-redis/src/main/kotlin/micro/apps/service/domain/product/.gitkeep -------------------------------------------------------------------------------- /services/spring-graphql-redis/src/main/kotlin/micro/apps/service/domain/user/models.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.service.domain.user 2 | 3 | import com.redis.om.spring.annotations.Bloom 4 | import com.redis.om.spring.annotations.Indexed 5 | import com.redis.om.spring.annotations.Searchable 6 | import org.springframework.data.annotation.Id 7 | import org.springframework.data.annotation.Reference 8 | import org.springframework.data.redis.core.RedisHash 9 | 10 | @RedisHash 11 | data class Role( 12 | @Id 13 | var id: String?, 14 | @Indexed 15 | var roleName: String? 16 | ) 17 | 18 | @RedisHash 19 | data class User( 20 | @Id 21 | val id: String?, 22 | @Indexed 23 | val firstName: String, 24 | @Indexed 25 | val middleName: String?, 26 | @Searchable 27 | val lastName: String, 28 | @Indexed 29 | @Bloom(name = "bf_user_email", capacity = 100000, errorRate = 0.001) 30 | var email: String, 31 | // HINT: Reference fields should be marked as nullable.??? 32 | @Reference 33 | val role: Role? 34 | ) 35 | -------------------------------------------------------------------------------- /services/spring-graphql-redis/src/main/kotlin/micro/apps/service/domain/user/repositories.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.service.domain.user 2 | 3 | import org.springframework.data.repository.CrudRepository 4 | import org.springframework.stereotype.Repository 5 | import java.util.* 6 | 7 | @Repository 8 | interface UserRepository : CrudRepository { 9 | fun findOneByLastName(lastName: String): Optional 10 | fun findByFirstNameAndLastName(firstName: String, lastName: String): List 11 | fun findByLastNameStartsWithIgnoreCase(lastName: String): List 12 | fun existsByEmail(email: String): Boolean 13 | } 14 | 15 | @Repository 16 | interface RoleRepository : CrudRepository { 17 | fun findOneByRoleName(roleName: String): Optional 18 | } 19 | -------------------------------------------------------------------------------- /services/spring-graphql-redis/src/main/resources/application-local.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | h2: 3 | console: 4 | enabled: false 5 | -------------------------------------------------------------------------------- /services/spring-graphql-redis/src/main/resources/application-production.yml: -------------------------------------------------------------------------------- 1 | # ==================== spring ============================== 2 | # Specify the DNS URI of your Redis cluster. 3 | spring: 4 | data: 5 | redis: 6 | host: redis-17814.c238.us-central1-2.gce.cloud.redislabs.com 7 | port: 17814 8 | # Specify the access key for your Redis cache. 9 | # password: 10 | 11 | # ==================== application properties ============= 12 | -------------------------------------------------------------------------------- /services/spring-graphql-redis/src/main/resources/application-test.yml: -------------------------------------------------------------------------------- 1 | debug: false 2 | # ==================== spring ============================== 3 | 4 | # ==================== application properties ============= 5 | application: 6 | runner: 7 | enabled: false 8 | -------------------------------------------------------------------------------- /services/spring-graphql-redis/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | shutdown: graceful 3 | # ==================== logging ============================= 4 | logging: 5 | level: 6 | micro.apps.service: DEBUG 7 | com.redis.om.spring: DEBUG 8 | # ==================== management ========================== 9 | management: 10 | info: 11 | env: 12 | enabled: true 13 | endpoint: 14 | health: 15 | show-details: always 16 | prometheus: 17 | enabled: true 18 | endpoints: 19 | web: 20 | exposure: 21 | include: health,info,metrics,env,prometheus,flyway 22 | prometheus: 23 | metrics: 24 | export: 25 | enabled: true 26 | # ==================== spring ============================== 27 | 28 | # ==================== application properties ============= 29 | features: 30 | change-events: 31 | enabled: true 32 | -------------------------------------------------------------------------------- /services/spring-graphql-redis/src/test/kotlin/micro/apps/service/ApplicationTests.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.service 2 | 3 | import org.junit.jupiter.api.Test 4 | import org.springframework.beans.factory.annotation.Autowired 5 | import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient 6 | import org.springframework.boot.test.context.SpringBootTest 7 | import org.springframework.test.web.reactive.server.WebTestClient 8 | 9 | @SpringBootTest 10 | @AutoConfigureWebTestClient 11 | class ApplicationTests(@Autowired private val webTestClient: WebTestClient) { 12 | 13 | @Test 14 | fun contextLoads() { 15 | // when 16 | 17 | // then 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /services/spring-graphql-redis/src/test/resources/config/application.yml: -------------------------------------------------------------------------------- 1 | # this config override src/main/resources/application.yml 2 | # and combined config is used by tests. 3 | # If we also set `spring.profiles.active=test` env for gradle test task, 4 | # src/main/resources/application-test.yml config also loaded and mixed. 5 | # beans tagged with @Profile("!test") are ignored. 6 | # ==================== spring ============================== 7 | spring: 8 | profiles: 9 | active: test 10 | -------------------------------------------------------------------------------- /services/spring-graphql-redis/src/test/resources/graphql-test/MUTATION.AddItem.gql: -------------------------------------------------------------------------------- 1 | mutation AddItem($input: ItemInput!) { 2 | addItem(input: $input) { 3 | id, 4 | name, 5 | description 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /services/spring-graphql-redis/src/test/resources/graphql-test/QUERY.ListItems.gql: -------------------------------------------------------------------------------- 1 | query ListItems { 2 | listItems { 3 | id, 4 | name, 5 | description 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /services/spring-kafka-functions/src/main/resources/application-production.yml: -------------------------------------------------------------------------------- 1 | # ========================== server ========================== 2 | spring: 3 | 4 | # ========================== kafka =========================== 5 | kafka: 6 | properties: 7 | # Broker 8 | bootstrap.servers: ${KAFKA_BOOTSTRAP_SERVERS:kafka:9092} 9 | sasl.mechanism: PLAIN 10 | sasl.jaas.config: ${SASL_JAAS_CONFIG_PROPERTY_FORMAT:org.apache.kafka.common.security.plain.PlainLoginModule required username='blah' password='blah'}" 11 | security.protocol: SASL_SSL 12 | # Schema Registry 13 | basic.auth.credentials.source: USER_INFO 14 | schema.registry.basic.auth.user.info: ${SCHEMA_REGISTRY_BASIC_AUTH_USER_INFO} 15 | schema.registry.url: ${SCHEMA_REGISTRY_URL:https://schema-registry:8081} 16 | 17 | -------------------------------------------------------------------------------- /services/spring-kafka-functions/src/test/kotlin/micro/apps/service/StreamsApplicationTest.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.service 2 | 3 | import io.kotest.core.spec.style.FunSpec 4 | import io.kotest.matchers.nulls.shouldNotBeNull 5 | import org.springframework.boot.test.context.SpringBootTest 6 | import org.springframework.core.env.Environment 7 | 8 | @SpringBootTest 9 | class StreamsApplicationTest(private val environment: Environment) : FunSpec({ 10 | test("application starts") { 11 | environment.shouldNotBeNull() 12 | } 13 | }) 14 | -------------------------------------------------------------------------------- /services/streams/src/main/resources/application-production.yml: -------------------------------------------------------------------------------- 1 | # ========================== server ========================== 2 | spring: 3 | 4 | # ========================== kafka =========================== 5 | kafka: 6 | properties: 7 | # Broker 8 | bootstrap.servers: ${KAFKA_BOOTSTRAP_SERVERS:kafka:9092} 9 | sasl.mechanism: PLAIN 10 | sasl.jaas.config: ${SASL_JAAS_CONFIG_PROPERTY_FORMAT:org.apache.kafka.common.security.plain.PlainLoginModule required username='blah' password='blah'}" 11 | security.protocol: SASL_SSL 12 | # Schema Registry 13 | basic.auth.credentials.source: USER_INFO 14 | schema.registry.basic.auth.user.info: ${SCHEMA_REGISTRY_BASIC_AUTH_USER_INFO} 15 | schema.registry.url: ${SCHEMA_REGISTRY_URL:https://schema-registry:8081} 16 | 17 | -------------------------------------------------------------------------------- /services/streams/src/test/kotlin/micro/apps/service/StreamsApplicationTest.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.service 2 | 3 | import io.kotest.core.spec.style.FunSpec 4 | import io.kotest.matchers.nulls.shouldNotBeNull 5 | import org.springframework.boot.test.context.SpringBootTest 6 | import org.springframework.core.env.Environment 7 | 8 | @SpringBootTest 9 | class StreamsApplicationTest(private val environment: Environment) : FunSpec({ 10 | test("application starts") { 11 | environment.shouldNotBeNull() 12 | } 13 | }) 14 | -------------------------------------------------------------------------------- /services/webapp/build.gradle.kts.bak: -------------------------------------------------------------------------------- 1 | import com.github.gradle.node.npm.task.NpmTask 2 | 3 | // import com.github.gradle.node.npm.task.NpxTask 4 | // import com.github.gradle.node.task.NodeTask 5 | 6 | plugins { 7 | // Ref: https://github.com/node-gradle/gradle-node-plugin/blob/master/docs/faq.md 8 | id("com.github.node-gradle.node") 9 | } 10 | 11 | node { 12 | val isCI = System.getenv("CI").isNullOrBlank().not() 13 | npmInstallCommand.set(if (isCI) "ci" else "install") 14 | version.set("16.4.2") 15 | npmVersion.set("7.18.1") 16 | download.set(false) 17 | } 18 | 19 | tasks { 20 | jar { 21 | dependsOn("npmBuild") 22 | from("build/dist") { 23 | into("static") 24 | } 25 | } 26 | 27 | register("run") { 28 | npmCommand.set(listOf("run", "dev")) 29 | args.addAll("--", "--open") 30 | } 31 | 32 | register("npmBuild") { 33 | dependsOn(npmInstall) 34 | npmCommand.set(listOf("run", "build")) 35 | } 36 | 37 | register("npmClean") { 38 | delete("build/dist") 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /services/wordcount/src/main/resources/application-production.yml: -------------------------------------------------------------------------------- 1 | # ========================== server ========================== 2 | spring: 3 | 4 | # ========================== kafka =========================== 5 | kafka: 6 | properties: 7 | # Broker 8 | bootstrap.servers: ${KAFKA_BOOTSTRAP_SERVERS:kafka:9092} 9 | sasl.mechanism: PLAIN 10 | sasl.jaas.config: ${SASL_JAAS_CONFIG_PROPERTY_FORMAT:org.apache.kafka.common.security.plain.PlainLoginModule required username='blah' password='blah'}" 11 | security.protocol: SASL_SSL 12 | # Schema Registry 13 | basic.auth.credentials.source: USER_INFO 14 | schema.registry.basic.auth.user.info: ${SCHEMA_REGISTRY_BASIC_AUTH_USER_INFO} 15 | schema.registry.url: ${SCHEMA_REGISTRY_URL:https://schema-registry:8081} 16 | 17 | -------------------------------------------------------------------------------- /services/wordcount/src/test/kotlin/micro/apps/service/WordcountApplicationTest.kt: -------------------------------------------------------------------------------- 1 | package micro.apps.service 2 | 3 | import io.kotest.core.spec.style.FunSpec 4 | import io.kotest.matchers.nulls.shouldNotBeNull 5 | import org.springframework.boot.test.context.SpringBootTest 6 | import org.springframework.core.env.Environment 7 | 8 | @SpringBootTest 9 | class WordcountApplicationTest(private val environment: Environment) : FunSpec({ 10 | test("application starts") { 11 | environment.shouldNotBeNull() 12 | } 13 | }) 14 | --------------------------------------------------------------------------------