|
1 | | -# E-commerce Microservices (Python, Flask, MySQL, SQS) |
2 | | - |
3 | | -Services |
4 | | - |
5 | | -- order_service (A): REST + MySQL + publishes SQS order events |
6 | | -- product_service (B): REST + MySQL (catalog) |
7 | | -- user_service (C): REST + MySQL (users) |
8 | | - |
9 | | -Infra |
10 | | - |
11 | | -- 3x MySQL containers |
12 | | -- LocalStack (SQS) |
13 | | -- Docker Compose to orchestrate |
14 | | - |
15 | | -Quick start |
16 | | - |
17 | | -- docker compose up -d --build |
18 | | -- docker compose logs -f order_service product_service user_service |
19 | | -- docker compose down -v |
20 | | - |
21 | | -APIs |
22 | | - |
23 | | -- OpenAPI specs in each service under openapi.yaml |
24 | | - |
25 | | -# E-commerce Microservices Architecture |
26 | | - |
27 | | -This repo contains three Python (Flask) microservices orchestrated with Docker Compose, each with its own MySQL database, plus LocalStack SQS for messaging. |
28 | | - |
29 | | -## Architecture (single diagram) |
30 | | - |
31 | | -```mermaid |
32 | | -flowchart LR |
33 | | - client([Client / Postman]) |
34 | | -
|
35 | | - subgraph "Order Service :8080" |
36 | | - order_svc([Order Service]) |
37 | | - o1["POST /api/v1/orders"] |
38 | | - o2["GET /api/v1/orders"] |
39 | | - o3["GET /api/v1/orders/{id}"] |
40 | | - o4["GET /api/v1/orders/{id}/details"] |
41 | | - o5["POST /api/v1/orders/{id}/pay"] |
42 | | - o6["POST /api/v1/orders/{id}/cancel"] |
43 | | - o7["GET /health"] |
44 | | - order_svc --- o1 |
45 | | - order_svc --- o2 |
46 | | - order_svc --- o3 |
47 | | - order_svc --- o4 |
48 | | - order_svc --- o5 |
49 | | - order_svc --- o6 |
50 | | - order_svc --- o7 |
51 | | - end |
52 | | -
|
53 | | - subgraph "Product Service :8081" |
54 | | - product_svc([Product Service]) |
55 | | - p1["CRUD /api/v1/products"] |
56 | | - p2["POST /api/v1/products/{id}/reserve"] |
57 | | - p3["POST /api/v1/products/{id}/release"] |
58 | | - p4["GET /api/v1/products/search"] |
59 | | - p5["GET /health"] |
60 | | - product_svc --- p1 |
61 | | - product_svc --- p2 |
62 | | - product_svc --- p3 |
63 | | - product_svc --- p4 |
64 | | - product_svc --- p5 |
65 | | - end |
66 | | -
|
67 | | - subgraph "User Service :8082" |
68 | | - user_svc([User Service]) |
69 | | - u1["POST /api/v1/users"] |
70 | | - u2["GET /api/v1/users/{id}"] |
71 | | - u3["POST /api/v1/login"] |
72 | | - u4["GET /health"] |
73 | | - user_svc --- u1 |
74 | | - user_svc --- u2 |
75 | | - user_svc --- u3 |
76 | | - user_svc --- u4 |
77 | | - end |
78 | | -
|
79 | | - subgraph Datastores |
80 | | - dborders[(MySQL order_db)] |
81 | | - dbproducts[(MySQL product_db)] |
82 | | - dbusers[(MySQL user_db)] |
83 | | - end |
84 | | -
|
85 | | - sqs[(LocalStack SQS: order-events)] |
86 | | -
|
87 | | - client --> order_svc |
88 | | - client --> product_svc |
89 | | - client --> user_svc |
90 | | -
|
91 | | - order_svc --> dborders |
92 | | - product_svc --> dbproducts |
93 | | - user_svc --> dbusers |
94 | | -
|
95 | | - order_svc --> user_svc |
96 | | - order_svc --> product_svc |
97 | | -
|
98 | | - order_svc --> sqs |
| 1 | +# E-Commerce Microservices |
| 2 | + |
| 3 | +[](https://python.org) |
| 4 | +[](https://flask.palletsprojects.com) |
| 5 | +[](https://docker.com) |
| 6 | +[](https://keploy.io) |
| 7 | + |
| 8 | +A Python/Flask e-commerce backend using microservices, each with its own MySQL database, an API Gateway, and SQS event messaging via LocalStack - all wired together with Docker Compose. |
| 9 | + |
| 10 | +--- |
| 11 | + |
| 12 | +## Services |
| 13 | + |
| 14 | +| Service | Port | Responsibility | |
| 15 | +|---|---|---| |
| 16 | +| API Gateway | `8083` | Single entry point - proxies all client requests | |
| 17 | +| Order Service | `8080` | Order lifecycle, stock reservation, SQS events | |
| 18 | +| Product Service | `8081` | Product catalog, inventory management | |
| 19 | +| User Service | `8082` | Auth, JWT issuance, user accounts & addresses | |
| 20 | +| LocalStack (SQS) | `4566` | Local AWS SQS - `order-events` queue | |
| 21 | + |
| 22 | +--- |
| 23 | + |
| 24 | +## Quick Start |
| 25 | + |
| 26 | +**Requires:** Docker Desktop (includes Compose) |
| 27 | + |
| 28 | +```bash |
| 29 | +git clone https://github.com/keploy/ecommerce_sample_app.git |
| 30 | +cd ecommerce_sample_app |
| 31 | +docker compose up -d --build |
| 32 | +``` |
| 33 | + |
| 34 | +That is it. On first boot the stack will: |
| 35 | +- Run all DB migrations automatically |
| 36 | +- Seed an admin user: `admin` / `admin123` |
| 37 | +- Seed sample products (Laptop, Mouse) |
| 38 | +- Create the `order-events` SQS queue |
| 39 | + |
| 40 | +**Health check:** |
| 41 | +```bash |
| 42 | +curl http://localhost:8083/health |
| 43 | +``` |
| 44 | + |
| 45 | +**Logs:** |
| 46 | +```bash |
| 47 | +docker compose logs -f |
| 48 | +``` |
| 49 | + |
| 50 | +**Teardown:** |
| 51 | +```bash |
| 52 | +docker compose down -v # -v removes data volumes |
| 53 | +``` |
| 54 | + |
| 55 | +--- |
| 56 | + |
| 57 | +## API |
| 58 | + |
| 59 | +All requests go through the gateway at `http://localhost:8083`. Every endpoint except `/api/v1/login` and `/health` requires `Authorization: Bearer <token>`. |
| 60 | + |
| 61 | +**Get a token:** |
| 62 | +```bash |
| 63 | +curl -s -X POST http://localhost:8083/api/v1/login \ |
| 64 | + -H "Content-Type: application/json" \ |
| 65 | + -d '{"username":"admin","password":"admin123"}' |
| 66 | +``` |
| 67 | + |
| 68 | +| Service | Endpoints | |
| 69 | +|---|---| |
| 70 | +| **User** | `POST /api/v1/login` , `POST /api/v1/users` , `GET /api/v1/users/{id}` , `GET/POST /api/v1/users/{id}/addresses` | |
| 71 | +| **Product** | `GET/POST /api/v1/products` , `GET/PUT/DELETE /api/v1/products/{id}` , `GET /api/v1/products/search` , `POST /api/v1/products/{id}/reserve` , `POST /api/v1/products/{id}/release` | |
| 72 | +| **Order** | `GET/POST /api/v1/orders` , `GET /api/v1/orders/{id}` , `GET /api/v1/orders/{id}/details` , `POST /api/v1/orders/{id}/pay` , `POST /api/v1/orders/{id}/cancel` | |
| 73 | + |
| 74 | +Full OpenAPI specs: each service has an `openapi.yaml`. Import `postman/collection.gateway.json` + `postman/environment.local.json` for a ready-to-run Postman setup. |
| 75 | + |
| 76 | +--- |
| 77 | + |
| 78 | +## Architecture |
| 79 | + |
| 80 | +``` |
| 81 | +Client --> API Gateway (:8083) |
| 82 | + |-- /users/* --> User Service (:8082) --> mysql-users (:3307) |
| 83 | + |-- /products/* --> Product Service (:8081) --> mysql-products (:3308) |
| 84 | + |-- /orders/* --> Order Service (:8080) --> mysql-orders (:3309) |
| 85 | + | |
| 86 | + |-- calls User Service (validate user) |
| 87 | + |-- calls Product Service (reserve / release stock) |
| 88 | + +-- publishes --> SQS order-events (LocalStack :4566) |
| 89 | +``` |
| 90 | + |
| 91 | +**Key behaviours:** |
| 92 | +- `POST /orders` validates the user, reserves product stock, persists the order, then emits an `ORDER_CREATED` event to SQS. |
| 93 | +- Supports `Idempotency-Key` header on order creation to prevent duplicates. |
| 94 | +- Cancelling an order releases reserved stock and emits `ORDER_CANCELLED`. |
| 95 | +- JWT (`HS256`) is issued by the User Service and verified by all services via a shared `JWT_SECRET`. |
| 96 | + |
| 97 | +--- |
| 98 | + |
| 99 | +## Testing |
| 100 | + |
| 101 | +Tests live in `<service>/keploy/` - two suites per service: |
| 102 | + |
| 103 | +| Suite | Description | |
| 104 | +|---|---| |
| 105 | +| `ai/` | AI-generated tests recorded from live traffic (e.g. 36 tests for `order_service`) | |
| 106 | +| `manual/` | Hand-crafted test scenarios (e.g. 14 tests for `order_service`) | |
| 107 | + |
| 108 | +**Run tests (requires [Keploy CLI](https://keploy.io/docs)):** |
| 109 | +```bash |
| 110 | +docker compose up -d --build |
| 111 | +keploy test -c "docker compose up" --container-name order_service |
99 | 112 | ``` |
100 | 113 |
|
101 | | -Key behaviors |
| 114 | +Coverage reports are written to `coverage/` during test runs. |
| 115 | + |
| 116 | +--- |
| 117 | + |
| 118 | +## Project Layout |
| 119 | + |
| 120 | +``` |
| 121 | +ecommerce_sample_app/ |
| 122 | +|-- docker-compose.yml |
| 123 | +|-- apigateway/ # Flask reverse proxy |
| 124 | +|-- order_service/ |
| 125 | +| |-- app.py |
| 126 | +| |-- migrations/ # Versioned SQL files - auto-applied at startup |
| 127 | +| +-- keploy/ai|manual/ # Keploy test suites |
| 128 | +|-- product_service/ # Same structure as order_service |
| 129 | +|-- user_service/ # Same structure as order_service |
| 130 | +|-- localstack/ # Queue init scripts (runs on LocalStack ready) |
| 131 | ++-- postman/ # Import-ready Postman collections |
| 132 | +``` |
| 133 | + |
| 134 | +--- |
| 135 | + |
| 136 | +## Configuration |
| 137 | + |
| 138 | +Set in `docker-compose.yml`. Key variables: |
| 139 | + |
| 140 | +| Variable | Default | Note | |
| 141 | +|---|---|---| |
| 142 | +| `JWT_SECRET` | `dev-secret-change-me` | **Must change in production** | |
| 143 | +| `DB_HOST / DB_USER / DB_PASSWORD / DB_NAME` | per-service | Each service owns its own DB | |
| 144 | +| `AWS_ENDPOINT` | `http://localstack:4566` | Routes SQS traffic to LocalStack | |
| 145 | +| `ADMIN_PASSWORD` | `admin123` | Seeded admin credentials | |
| 146 | + |
| 147 | +--- |
| 148 | + |
| 149 | +## Contributing |
102 | 150 |
|
103 | | -- Order creation validates user and products, reserves stock, persists order + items, emits SQS event. |
104 | | -- Idempotency: POST /orders supports Idempotency-Key to avoid duplicate orders. |
105 | | -- Status transitions: PENDING → PAID or CANCELLED (cancel releases stock). |
| 151 | +1. Fork and create a branch (`feat/your-feature`, `fix/issue`, `docs/update`) |
| 152 | +2. Make changes - keep services decoupled, update `openapi.yaml` for API changes, add new migration files for schema changes (never edit existing ones) |
| 153 | +3. Test: `docker compose up -d --build` then run Keploy tests |
| 154 | +4. Commit using [Conventional Commits](https://www.conventionalcommits.org) (`feat:`, `fix:`, `docs:`, `test:`, `refactor:`) |
| 155 | +5. Open a Pull Request and reference the related issue |
0 commit comments