{"id":52128371,"url":"https://github.com/robertograham/payment-gateway","last_synced_at":"2026-08-05T12:01:11.095Z","repository":{"id":344417280,"uuid":"1181701250","full_name":"RobertoGraham/payment-gateway","owner":"RobertoGraham","description":null,"archived":false,"fork":false,"pushed_at":"2026-03-15T00:58:25.000Z","size":444,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-03-15T02:05:32.167Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Java","has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/RobertoGraham.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-03-14T14:04:49.000Z","updated_at":"2026-03-15T00:58:27.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/RobertoGraham/payment-gateway","commit_stats":null,"previous_names":["robertograham/payment-gateway"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/RobertoGraham/payment-gateway","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RobertoGraham%2Fpayment-gateway","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RobertoGraham%2Fpayment-gateway/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RobertoGraham%2Fpayment-gateway/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RobertoGraham%2Fpayment-gateway/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/RobertoGraham","download_url":"https://codeload.github.com/RobertoGraham/payment-gateway/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RobertoGraham%2Fpayment-gateway/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":36311008,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-07-20T02:08:10.276Z","status":"online","status_checked_at":"2026-08-05T02:00:06.619Z","response_time":104,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-08-05T12:01:10.447Z","updated_at":"2026-08-05T12:01:11.075Z","avatar_url":"https://github.com/RobertoGraham.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# payment-gateway\n\n**payment-gateway** is a domain-driven, modular application that enables merchants to accept online\npayments through a RESTful API.\n\n[![Build payment-gateway](https://github.com/RobertoGraham/payment-gateway/actions/workflows/build-payment-gateway.yaml/badge.svg)](https://github.com/RobertoGraham/payment-gateway/actions/workflows/build-payment-gateway.yaml)\n\nTo get started, you will need:\n\n- [Docker](https://www.docker.com/products/docker-desktop) - to start the bank simulator.\n- [JDK 25](https://bell-sw.com/pages/downloads/#jdk-25-lts) - to compile and run payment-gateway.\n\n## Getting started\n\nStart the bank simulator.\n\n```shell\ndocker compose up --detach bank_simulator\n```\n\nCompile and run payment-gateway.\n\n```shell\n./gradlew bootRun\n```\n\nTo visualize and interact with the API's resources, navigate\nto http://localhost:8090/swagger-ui.html from a web browser.\n\n## Architecture\n\nI have built payment-gateway following the principles of domain-driven design and the hexagonal\narchitecture pattern. It is\na [multi-project Gradle build](https://docs.gradle.org/current/userguide/multi_project_builds.html)\ncomprised of 5 subprojects (modules), each representing a distinct layer: one domain module\ncontaining all business logic and port interfaces, one application module acting as the composition\nroot, and three adapter modules implementing the driving (web) and driven (acquiring bank, payment\nrepository) sides of the hexagonal architecture.\n\n### [payment-gateway-domain](payment-gateway-domain)\n\nThe domain layer at the centre of payment-gateway that all other modules depend on. It requires zero\nruntime dependencies and is agnostic of any specific technology or framework. It contains the:\n\n- Domain model.\n- Driving and driven ports.\n- Domain services.\n\n### [payment-gateway-adapter-web](payment-gateway-adapter-web)\n\nThe driving adapter RESTful API through which merchants can interact with payment-gateway.\n\n#### POST /payments\n\nConnects merchants to the `ProcessPaymentUseCase` driving port, allowing them to process payments.\n\nRequest:\n\n```http\nPOST /payments HTTP/1.1\nContent-Type: application/json\nHost: localhost:8090\n\n{\n  \"cardNumber\": \"4242424242424242\",\n  \"expiryMonth\": 1,\n  \"expiryYear\": 2030,\n  \"currency\": \"GBP\",\n  \"amount\": 1,\n  \"cvv\": \"123\"\n}\n```\n\nResponses:\n\n```http\nHTTP/1.1 201 Created\nContent-Type: application/json\n\n{\n  \"id\": \"00000000-0000-0000-0000-000000000000\",\n  \"status\": \"Authorized\",\n  \"last4Digits\": \"4242\",\n  \"expiryMonth\": 1,\n  \"expiryYear\": 2030,\n  \"currency\": \"GBP\",\n  \"amount\": 1\n}\n```\n\n```http\nHTTP/1.1 400 Bad Request\nContent-Type: application/problem+json\n\n{\n  \"detail\": \"Rejected\",\n  \"instance\": \"/payments\",\n  \"status\": 400,\n  \"title\": \"Bad Request\"\n}\n```\n\n```http\nHTTP/1.1 422 Unprocessable Content\nContent-Type: application/problem+json\n\n{\n  \"detail\": \"Rejected\",\n  \"instance\": \"/payments\",\n  \"status\": 422,\n  \"title\": \"Unprocessable Content\"\n}\n```\n\n```http\nHTTP/1.1 502 Bad Gateway\nContent-Type: application/problem+json\n\n{\n  \"instance\": \"/payments\",\n  \"status\": 502,\n  \"title\": \"Bad Gateway\"\n}\n```\n\n#### GET /payment/{id}\n\nConnects merchants to the `RetrievePaymentQuery` driving port, allowing them to retrieve payments.\n\nRequest:\n\n```http\nGET /payment/00000000-0000-0000-0000-000000000000 HTTP/1.1\nHost: localhost:8090\n```\n\nResponses:\n\n```http\nHTTP/1.1 200 OK\nContent-Type: application/json\n\n{\n  \"id\": \"00000000-0000-0000-0000-000000000000\",\n  \"status\": \"Declined\",\n  \"last4Digits\": \"4242\",\n  \"expiryMonth\": 1,\n  \"expiryYear\": 2030,\n  \"currency\": \"GBP\",\n  \"amount\": 1\n}\n```\n\n```http\nHTTP/1.1 404 Not Found\n```\n\n### [payment-gateway-adapter-acquiring-bank](payment-gateway-adapter-acquiring-bank)\n\nThe driven adapter that connects the domain layer to the acquiring bank's API by\nimplementing the `AcquiringBankPort` driven port. It ensures resilience by applying a combination of\nretry and circuit breaker policies to acquiring bank payment authorization requests.\n\n### [payment-gateway-adapter-payment-repository](payment-gateway-adapter-payment-repository)\n\nThe driven adapter that connects the domain layer to a payment repository by implementing the\n`PaymentRepositoryPort` driven port. It allows the domain layer to persist and retrieve payment\ninformation without being coupled to any specific database technology. I chose a `ConcurrentHashMap`\nimplementation to support safe, concurrent access by multiple threads.\n\n### [payment-gateway-application](payment-gateway-application)\n\nThe composition root of payment-gateway where the domain and adapter modules are composed together\ninto a working application. Adapter modules are runtime-only dependencies, as they're effectively\nSpring Boot starters that contain all the necessary configuration to be auto-discovered and\nautoconfigured by Spring Boot.\n\n## Improvements\n\n- Require merchants to supply idempotency keys with payment processing requests to prevent duplicate\n  payments in the event of retries.\n- Tweak the retry and circuit breaker policies to match the acquiring bank's real-world behaviour\n  and SLAs.\n- Replace the current payment repository adapter with a more robust, production-ready implementation\n  that connects to a real database.\n- Improve the observability of the application by recording and exporting metrics such as\n  authorization rate, decline volume, API response times, etc.\n- Expand the suite of tests to include:\n  - Merchant-centric acceptance tests.\n  - Performance tests.\n- Implement API security:\n  - RBAC to restrict access to authorized merchants.\n  - Rate limiting to prevent abuse and ensure fair usage.\n  - DDoS protection to prevent abuse and ensure availability.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frobertograham%2Fpayment-gateway","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frobertograham%2Fpayment-gateway","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frobertograham%2Fpayment-gateway/lists"}