{"id":25188860,"url":"https://github.com/makiato1999/payplus","last_synced_at":"2026-06-24T21:31:25.717Z","repository":{"id":274599477,"uuid":"923322096","full_name":"Makiato1999/PayPlus","owner":"Makiato1999","description":"PayPlus: Payment Platform with MVC \u0026 DDD Architecture","archived":false,"fork":false,"pushed_at":"2025-07-14T22:31:07.000Z","size":5361,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-07-15T03:10:45.554Z","etag":null,"topics":["domain-driven-design","model-view-controller"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Makiato1999.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-01-28T02:47:16.000Z","updated_at":"2025-07-14T22:31:11.000Z","dependencies_parsed_at":"2025-04-19T09:41:57.176Z","dependency_job_id":"26da0e95-7221-4feb-9ee1-e7a8256aa439","html_url":"https://github.com/Makiato1999/PayPlus","commit_stats":null,"previous_names":["makiato1999/payplus"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/Makiato1999/PayPlus","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Makiato1999%2FPayPlus","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Makiato1999%2FPayPlus/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Makiato1999%2FPayPlus/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Makiato1999%2FPayPlus/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Makiato1999","download_url":"https://codeload.github.com/Makiato1999/PayPlus/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Makiato1999%2FPayPlus/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34750952,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-24T02:00:07.484Z","response_time":106,"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":["domain-driven-design","model-view-controller"],"created_at":"2025-02-09T20:30:40.064Z","updated_at":"2026-06-24T21:31:25.710Z","avatar_url":"https://github.com/Makiato1999.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# PayPlus\n\nPayPlus is a virtual-product order and payment system implemented twice in the same repository:\n\n- `payplus-mvc`: a classic layered MVC version\n- `payplus-ddd`: a DDD-style refactor of the same business flow\n\nThe project focuses on the full payment lifecycle rather than a single SDK integration: order creation, Alipay checkout, async callback verification, order state transition, timeout closing, missing-callback compensation, and WeChat QR-code login.\n\n## Why This Repository Exists\n\nThis repository is useful for comparing how the same payment business can be modeled in two styles:\n\n- MVC for straightforward feature delivery\n- DDD for better separation of business rules, infrastructure, and extension points\n\nThe DDD version is the stronger reference if you want to understand how the payment flow was decomposed into domain services, repositories, strategy selection, and adapter ports.\n\n## Business Scope\n\nThe current codebase covers these scenarios:\n\n- Create an order for a virtual product\n- Generate an Alipay page-payment request\n- Accept Alipay async callbacks and verify the signature\n- Update order status to paid after successful callback\n- Scan unpaid orders on a schedule\n- Close orders that stay unpaid for too long\n- Compensate for missing or failed payment callbacks by actively querying Alipay\n- Support WeChat QR-code login and cache login state locally\n\n## Tech Stack\n\n- Java 8\n- Spring Boot 2.7.x\n- MyBatis\n- MySQL\n- Alipay Java SDK\n- Retrofit2\n- Guava Cache\n- Guava EventBus\n- Docker Compose\n\nNotes:\n\n- The current implementation uses `Guava Cache` for local caching.\n- Redis appears in deployment files, but Redis is not the active cache implementation in the business code.\n\n## Repository Layout\n\n```text\nPayPlus/\n├── payplus-ddd/\n│   ├── payplus-ddd-api/             # API contracts and DTOs\n│   ├── payplus-ddd-app/             # Spring Boot app, configs, MyBatis resources\n│   ├── payplus-ddd-domain/          # Core domain model and domain services\n│   ├── payplus-ddd-infrastructure/  # Repository impls, external gateways, payment ports\n│   ├── payplus-ddd-trigger/         # Controllers, jobs, listeners\n│   └── payplus-ddd-types/           # Shared constants, exceptions, events, SDK helpers\n├── payplus-mvc/\n│   ├── payplus-common/              # Shared constants, exceptions, utilities\n│   ├── payplus-dao/                 # DAO interfaces\n│   ├── payplus-domain/              # Request/response/domain objects\n│   ├── payplus-service/             # Service layer\n│   └── payplus-web/                 # Controllers, jobs, app bootstrap, resources\n└── README.md\n```\n\n## Core Flow\n\n### 1. Order creation\n\nThe system receives `userId` and `productId`, checks whether the user already has an unpaid order for the same product, and reuses that order if possible.\n\nIf no reusable order exists:\n\n- query product info\n- create a local order record in MySQL\n- call Alipay to generate a payment page\n- persist `payUrl` and move the order into waiting-for-payment status\n\n### 2. Payment callback\n\nAfter the user pays through Alipay:\n\n- Alipay calls the async notify endpoint\n- the server checks `trade_status`\n- the callback signature is verified with Alipay's public key\n- the local order is updated to paid\n\nThis is the key \"order -\u003e payment -\u003e callback -\u003e state update\" business loop.\n\n### 3. Compensation and timeout handling\n\nThe system does not rely on async callbacks alone.\n\n- `NoPayNotifyOrderJob` scans orders that remain unpaid and actively queries Alipay\n- `TimeoutCloseOrderJob` closes orders that have stayed unpaid for too long\n\nThis design reduces the risk of local order status drifting from the real payment result.\n\n### 4. WeChat login\n\nThe WeChat login flow works like this:\n\n- request a QR-code ticket from WeChat\n- let the client display the QR code\n- receive the scan event from the WeChat portal callback\n- map `ticket -\u003e openId` in local cache\n- poll login status from the frontend\n\n`access_token` and login state are cached with Guava.\n\n## Architecture Comparison\n\n### MVC Version\n\nThe MVC implementation keeps most business flow in the service layer:\n\n- controllers accept requests\n- services orchestrate order creation and payment logic\n- DAOs read and write MySQL\n\nThis version is easier to read at first glance and is suitable for fast iteration, but payment-specific rules and integration logic tend to accumulate inside service classes.\n\n### DDD Version\n\nThe DDD implementation separates responsibilities more explicitly:\n\n- `trigger`: HTTP entrypoints, jobs, listeners\n- `domain`: business rules, order service, payment service, aggregates, value objects\n- `infrastructure`: DAO implementations, third-party gateways, port adapters\n- `api/types/app`: contracts, configs, shared objects\n\nImportant examples in the DDD version:\n\n- `OrderService`: domain orchestration for order creation\n- `PaymentService`: delegates prepay behavior to payment ports\n- `PaymentStrategyFactory`: resolves the payment implementation by pay method\n- `OrderRepository`: persistence and event publication\n- `AlipayPort`: Alipay-specific prepay integration\n- `LoginPort`: WeChat-specific gateway integration\n\nThis structure makes it easier to extend payment methods without rewriting core order logic.\n\n## Key Files to Read First\n\nIf you want a fast code walkthrough, start here:\n\n- `payplus-ddd/payplus-ddd-trigger/src/main/java/com/payplus/trigger/http/AlipayController.java`\n- `payplus-ddd/payplus-ddd-domain/src/main/java/com/payplus/domain/order/service/AbstractOrderService.java`\n- `payplus-ddd/payplus-ddd-domain/src/main/java/com/payplus/domain/order/service/OrderService.java`\n- `payplus-ddd/payplus-ddd-domain/src/main/java/com/payplus/domain/payment/service/PaymentService.java`\n- `payplus-ddd/payplus-ddd-domain/src/main/java/com/payplus/domain/payment/service/strategy/PaymentStrategyFactory.java`\n- `payplus-ddd/payplus-ddd-infrastructure/src/main/java/com/payplus/infrastructure/adapter/repository/OrderRepository.java`\n- `payplus-ddd/payplus-ddd-trigger/src/main/java/com/payplus/trigger/job/NoPayNotifyOrderJob.java`\n- `payplus-ddd/payplus-ddd-trigger/src/main/java/com/payplus/trigger/job/TimeoutCloseOrderJob.java`\n- `payplus-ddd/payplus-ddd-trigger/src/main/java/com/payplus/trigger/http/LoginController.java`\n- `payplus-ddd/payplus-ddd-trigger/src/main/java/com/payplus/trigger/http/WeChatPortalController.java`\n\n## Database\n\nBoth implementations use a single core table: `pay_order`.\n\nSchema files:\n\n- DDD: `payplus-ddd/docs/dev-ops/mysql/sql/payplus-mall.sql`\n- MVC: `payplus-mvc/docs/dev-ops/mysql/sql/s-pay-mall.sql`\n\nImportant fields:\n\n- `order_id`\n- `user_id`\n- `product_id`\n- `status`\n- `pay_url`\n- `pay_time`\n\nTypical status values used by the code:\n\n- `CREATE`\n- `PAY_WAIT`\n- `PAY_SUCCESS`\n- `CLOSE`\n\n## Local Run\n\nThe project contains environment-specific YAML files and Docker resources, but before running locally you should review and replace all environment-dependent values.\n\n### Prerequisites\n\n- JDK 8\n- Maven\n- MySQL 8.x\n\n### Basic steps\n\n1. Create the database from the SQL file that matches the implementation you want to run.\n2. Update the datasource in the corresponding `application-*.yml`.\n3. Replace demo or local-only payment and WeChat configuration values.\n4. Start either the MVC app or the DDD app.\n\nTypical app entrypoints:\n\n- MVC: `payplus-mvc/payplus-web/src/main/java/com/payplus/Application.java`\n- DDD: `payplus-ddd/payplus-ddd-app/src/main/java/com/payplus/Application.java`\n\n### Maven modules\n\n- MVC root: `payplus-mvc/pom.xml`\n- DDD root: `payplus-ddd/pom.xml`\n\n## API Endpoints\n\nMain HTTP endpoints in the DDD version:\n\n- `POST /api/v1/alipay/create_pay_order`\n- `POST /api/v1/alipay/alipay_notify_url`\n- `GET /api/v1/login/wechat_qrcode_ticket`\n- `GET /api/v1/login/check_login`\n- `GET /api/v1/wechat/portal/receive`\n- `POST /api/v1/wechat/portal/receive`\n\nThe MVC version exposes the same business endpoints with the same overall flow.\n\n## Testing\n\nThe repository contains basic Spring Boot tests and a small Alipay sandbox test class.\n\nExamples:\n\n- `payplus-ddd/payplus-ddd-app/src/test/java/com/payplus/test/domain/OrderServiceTest.java`\n- `payplus-mvc/payplus-web/src/test/java/com/payplus/test/web/AliPayTest.java`\n\nThe tests are more like development verification samples than a full automated regression suite.\n\n## Interview / Learning Angles\n\nThis repository is a good example for discussing:\n\n- how to build a payment order lifecycle\n- why async callbacks need signature verification\n- why callback-only status update is not enough\n- how to design compensation jobs for eventual consistency\n- how to compare MVC and DDD in a concrete business system\n- how to decouple payment channels with a strategy factory and port abstraction\n\nFor interview preparation in Chinese, see `NOTE.md`.\n\n## Caveats\n\n- Configuration files contain environment-specific values and demo credentials; treat them as local examples and replace them before real use.\n- Redis is not actively wired into the business flow even though related deployment files exist.\n- Product data is currently mocked through a local RPC-style adapter rather than a real external product service.\n\n## License\n\nApache License 2.0. See `LICENSE`.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmakiato1999%2Fpayplus","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmakiato1999%2Fpayplus","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmakiato1999%2Fpayplus/lists"}