|
1 | | -# NexusFlow: Enterprise Order Processor |
| 1 | +# NexusFlow Enterprise Order Processor |
2 | 2 |
|
3 | | -NexusFlow is a **senior-level enterprise order processing platform** engineered for high concurrency, scalability, and data integrity. It orchestrates a secure Spring Boot backend with a responsive React frontend, utilizing event-driven architecture to handle complex workflows efficiently. |
| 3 | +NexusFlow is a Spring Boot + React order-processing system that demonstrates enterprise backend design, secure role-based workflows, PostgreSQL persistence, and RabbitMQ-driven async order handling. |
4 | 4 |
|
5 | | -## 🌟 Key Features |
| 5 | +## Problem It Solves |
6 | 6 |
|
7 | | -### 1. Robust Data Integrity (Optimistic Locking) |
8 | | -- **Problem**: In high-concurrency environments, multiple users might attempt to purchase the last item simultaneously ("The Lost Update" problem). |
9 | | -- **Solution**: Implemented JPA `@Version` based optimistic locking on `Product` entities. |
10 | | -- **Outcome**: Ensures strict ACID compliance. If concurrent transactions conflict, the system detects the version mismatch and handles the `ObjectOptimisticLockingFailureException` gracefully, preventing negative stock and ensuring data consistency. |
| 7 | +Enterprise order systems need to validate inventory, reserve stock, process payments, expose operational order workflows, and keep an audit trail without letting controllers become business-logic dumping grounds. NexusFlow models that flow in a compact portfolio project that is realistic enough for senior Java/Spring interviews without pretending to be a full ERP. |
11 | 8 |
|
12 | | -### 2. Event-Driven Architecture (RabbitMQ) |
13 | | -- **Decoupling**: Order placement is decoupled from heavy post-processing tasks (inventory sync, notifications, analytics). |
14 | | -- **Resilience**: Uses **RabbitMQ** to buffer events. If downstream services fail, messages persist in the `order_placed_queue` for retry, ensuring zero data loss. |
15 | | -- **Performance**: shifting heavy lifting to async workers reduces the Order API response time to ~100ms, compared to seconds in synchronous systems. |
| 9 | +## Tech Stack |
16 | 10 |
|
17 | | -### 3. Enterprise-Grade Security |
18 | | -- **Stateless Authentication**: Secured via **Spring Security** and **JWT (JSON Web Tokens)**. |
19 | | -- **Role-Based Access Control (RBAC)**: Fine-grained permissions for `User` and `Admin` roles protecting sensitive endpoints. |
| 11 | +- Backend: Java 17, Spring Boot 3.2, Spring Web, Spring Data JPA, Spring Security, JWT, Spring AMQP, Actuator, OpenAPI |
| 12 | +- Frontend: React 19, TypeScript, Vite, React Router, Axios, vanilla CSS |
| 13 | +- Data and infrastructure: PostgreSQL 15, Flyway, RabbitMQ Management, Docker Compose |
| 14 | +- Testing: JUnit 5, Mockito, Spring MVC tests, Spring Data JPA tests, Testcontainers for PostgreSQL when Docker is available |
| 15 | +- CI: GitHub Actions for backend verification, frontend build, and frontend lint |
20 | 16 |
|
21 | | -### 4. Comprehensive Input Validation |
22 | | -- **Bean Validation**: All DTOs validated with `@Valid`, `@NotNull`, `@Min`, `@Max`, `@NotBlank` annotations. |
23 | | -- **Detailed Error Messages**: User-friendly validation error responses with field-specific messages. |
| 17 | +## Architecture |
24 | 18 |
|
25 | | -### 5. Advanced Exception Handling |
26 | | -- **Custom Exceptions**: `ResourceNotFoundException`, `InsufficientStockException` for business logic errors. |
27 | | -- **Optimistic Locking Handler**: Graceful handling of concurrent modification conflicts. |
28 | | -- **Structured Error Responses**: Consistent error format with timestamp, status, message, and validation errors. |
| 19 | +The backend uses a pragmatic package structure: |
29 | 20 |
|
30 | | -### 6. API Documentation (Swagger/OpenAPI) |
31 | | -- **Interactive API Explorer**: Full REST API documentation with try-it-out functionality. |
32 | | -- **JWT Integration**: Built-in authentication support in Swagger UI. |
| 21 | +- `domain/model`: JPA entities and enums |
| 22 | +- `application/service`: business rules, state machine, metrics |
| 23 | +- `infrastructure/persistence`: Spring Data repositories |
| 24 | +- `infrastructure/messaging`: transactional outbox, RabbitMQ configuration, message DTOs, publisher, consumer |
| 25 | +- `web/controller` and `web/dto`: REST API and DTO boundaries |
| 26 | +- `security`, `config`, `exception`: JWT/RBAC, CORS, request correlation, health, structured errors |
33 | 27 |
|
34 | | -### 7. Observability & Monitoring |
35 | | -- **Spring Actuator**: Health checks, metrics, and application monitoring endpoints. |
36 | | -- **Structured Logging**: SLF4J with contextual logging across all services. |
37 | | - |
38 | | -## 🏗 System Architecture |
39 | | - |
40 | | -The system follows a microservices-inspired architecture managed via Docker Compose: |
| 28 | +```mermaid |
| 29 | +flowchart LR |
| 30 | + User[React UI] --> API[Spring Boot REST API] |
| 31 | + API --> Auth[JWT + RBAC] |
| 32 | + API --> Service[Order Application Service] |
| 33 | + Service --> DB[(PostgreSQL + Flyway)] |
| 34 | + Service --> Outbox[Transactional Outbox] |
| 35 | + Outbox --> DB |
| 36 | + Outbox --> MQ[RabbitMQ Topic Exchange] |
| 37 | + MQ --> Worker[Async Order Worker] |
| 38 | + Worker --> Service |
| 39 | + API --> Actuator[Actuator + Metrics] |
| 40 | +``` |
41 | 41 |
|
42 | | -1. **Frontend**: React (Vite) + TypeScript for a type-safe, performant UI. |
43 | | -2. **Backend**: Spring Boot 3.2 REST API. |
44 | | -3. **Database**: PostgreSQL 15 (Relational/ACID). |
45 | | -4. **Message Broker**: RabbitMQ (Async messaging). |
| 42 | +## Order Lifecycle |
46 | 43 |
|
47 | | -### Architecture Diagram |
48 | 44 | ```mermaid |
49 | | -graph TD |
50 | | - Client[React Client] -->|REST API| Server[Spring Boot Server] |
51 | | - Server -->|Read/Write| DB[(PostgreSQL)] |
52 | | - Server -->|Publish Event| MQ[RabbitMQ] |
53 | | - MQ -->|Consume Event| Listener["Async Worker (Internal)"] |
| 45 | +stateDiagram-v2 |
| 46 | + [*] --> CREATED |
| 47 | + CREATED --> VALIDATED: stock reserved |
| 48 | + VALIDATED --> PAID: payment captured |
| 49 | + PAID --> PROCESSING: async worker |
| 50 | + PROCESSING --> SHIPPED: async worker or manager |
| 51 | + SHIPPED --> DELIVERED: manager |
| 52 | + CREATED --> CANCELLED |
| 53 | + VALIDATED --> CANCELLED |
| 54 | + PAID --> CANCELLED |
| 55 | + CREATED --> FAILED |
| 56 | + VALIDATED --> FAILED |
| 57 | + PAID --> FAILED |
| 58 | + PROCESSING --> FAILED |
54 | 59 | ``` |
55 | 60 |
|
56 | | -## 🛠 Tech Stack |
| 61 | +## Key Features |
57 | 62 |
|
58 | | -### Backend |
59 | | -- **Framework**: Spring Boot 3.2 |
60 | | -- **Language**: Java 17 |
61 | | -- **Data**: Spring Data JPA, PostgreSQL |
62 | | -- **Security**: Spring Security, JWT (io.jsonwebtoken) |
63 | | -- **Messaging**: Spring AMQP (RabbitMQ) |
64 | | -- **Tools**: Lombok, Maven |
| 63 | +- Validated order creation with stock reservation and idempotency key support |
| 64 | +- Payment simulation that commits or releases reserved inventory |
| 65 | +- Enforced order status transitions with clear `409 Conflict` responses |
| 66 | +- Order audit history for lifecycle changes with actor and correlation ID |
| 67 | +- Paged, filterable, sortable order listing |
| 68 | +- Flyway-managed database schema |
| 69 | +- Transactional outbox for RabbitMQ status-change events |
| 70 | +- RabbitMQ durable queue and dead-letter queue |
| 71 | +- Async worker that advances paid orders into processing and shipped states |
| 72 | +- JWT authentication with `USER`, `MANAGER`, and `ADMIN` roles |
| 73 | +- BCrypt password hashing and seeded demo users |
| 74 | +- DTO-based REST API responses instead of leaking JPA entity graphs |
| 75 | +- Structured error responses with validation details and correlation IDs |
| 76 | +- Actuator health and order-processing health indicator |
| 77 | +- React dashboard for order creation, payment, cancellation, and history |
| 78 | +- Operations UI for inventory visibility and staff order transitions |
65 | 79 |
|
66 | | -### Frontend |
67 | | -- **Framework**: React 19 |
68 | | -- **Build Tool**: Vite 7 |
69 | | -- **Language**: TypeScript 5 |
70 | | -- **Routing**: React Router DOM 7 |
71 | | -- **HTTP Client**: Axios |
72 | | -- **Styling**: Vanilla CSS (Modular & Responsive) |
| 80 | +## Security |
73 | 81 |
|
74 | | -## 🚀 Getting Started |
| 82 | +- Public endpoints: `/api/auth/register`, `/api/auth/login`, Swagger, API docs, health |
| 83 | +- Authenticated endpoints: product list, order creation/list/detail/payment/status |
| 84 | +- Staff endpoints: inventory and operational order actions |
| 85 | +- Admin-only endpoints: create/update/delete products |
| 86 | +- Sensitive values are read from environment variables; see `.env.example` |
| 87 | +- Public registration creates `ROLE_USER` only; staff users are seeded for local demo |
75 | 88 |
|
76 | | -### Quickstart (Docker Compose) |
77 | | -- `docker-compose up --build` |
78 | | -- Frontend: http://localhost:5173 |
79 | | -- API: http://localhost:8080 |
80 | | -- Swagger: http://localhost:8080/swagger-ui.html (use the token field to authorize) |
81 | | -- Health/Metrics: http://localhost:8080/actuator/health, http://localhost:8080/actuator/metrics |
82 | | -- RabbitMQ UI: http://localhost:15672 (guest/guest) |
| 89 | +## Async Processing |
| 90 | + |
| 91 | +When an order reaches `PAID`, the order transaction stores an `ORDER_STATUS_CHANGED` message in `outbox_events` with a correlation ID. A scheduled relay publishes pending outbox rows to the `nexusflow.orders` topic exchange and marks them `PUBLISHED`, `FAILED`, or `DEAD` based on retry outcome. The RabbitMQ consumer listens on `nexusflow.order-events` and advances paid orders to `PROCESSING` and then `SHIPPED`. Failed RabbitMQ deliveries route to `nexusflow.order-events.dlq`. |
83 | 92 |
|
84 | | -### Prerequisites |
85 | | -- [Docker Desktop](https://www.docker.com/products/docker-desktop/) (Required) |
86 | | -- Java 17+ & Node.js 18+ (Optional, for local non-Docker dev) |
| 93 | +## Run Locally |
87 | 94 |
|
88 | | -### Deployment (Recommended) |
89 | | -Run the entire stack with a single command: |
| 95 | +Prerequisites: Docker Desktop. |
90 | 96 |
|
91 | 97 | ```bash |
92 | | -docker-compose up --build |
| 98 | +docker compose --env-file .env.example up --build |
93 | 99 | ``` |
94 | 100 |
|
95 | | -**Access Points**: |
96 | | -- **Frontend**: [http://localhost:5173](http://localhost:5173) |
97 | | -- **Backend API**: [http://localhost:8080](http://localhost:8080) |
98 | | -- **Swagger UI**: [http://localhost:8080/swagger-ui.html](http://localhost:8080/swagger-ui.html) |
99 | | -- **API Docs**: [http://localhost:8080/api-docs](http://localhost:8080/api-docs) |
100 | | -- **Health Check**: [http://localhost:8080/actuator/health](http://localhost:8080/actuator/health) |
101 | | -- **Metrics**: [http://localhost:8080/actuator/metrics](http://localhost:8080/actuator/metrics) |
102 | | -- **RabbitMQ Dashboard**: [http://localhost:15672](http://localhost:15672) (User: `guest`, Pass: `guest`) |
103 | | - |
104 | | -### Local Development (Optional) |
105 | | -- Backend: `cd server && mvn spring-boot:run` |
106 | | -- Frontend: `cd client && npm install && npm run dev` |
107 | | -- Tests: `cd server && mvn test` |
108 | | -- Frontend build check: `cd client && npm run build` |
109 | | -- Health check: `curl http://localhost:8080/actuator/health` |
110 | | - |
111 | | -### Auth & Roles |
112 | | -- Register or login at `/api/auth/register` or `/api/auth/login` (Swagger is the fastest way to try it). |
113 | | -- In Swagger, paste the JWT in **Authorize** without the `Bearer` prefix. |
114 | | -- Default role: `ROLE_CUSTOMER`; promote to admin manually or use the seeded admin credentials below. |
115 | | - |
116 | | -### Dev seed (auto) |
117 | | -- Default admin (dev/demo): `admin` / `admin123` (seed is enabled when `SEED_ENABLED=true`, default). |
118 | | -- Sample products are auto-created when the DB is empty. |
119 | | - |
120 | | -### Promote to Admin (quick SQL) |
121 | | -```sql |
122 | | -update users set role = 'ROLE_ADMIN' where username = 'your_username'; |
| 101 | +Access points: |
| 102 | + |
| 103 | +- Frontend: http://localhost:5173 |
| 104 | +- Backend API: http://localhost:8080 |
| 105 | +- Swagger UI: http://localhost:8080/swagger-ui.html |
| 106 | +- API docs: http://localhost:8080/api-docs |
| 107 | +- Health: http://localhost:8080/actuator/health |
| 108 | +- RabbitMQ dashboard: http://localhost:15672 |
| 109 | + |
| 110 | +Demo credentials from seed data: |
| 111 | + |
| 112 | +- User: `user` / `user12345` |
| 113 | +- Manager: `manager` / `manager123` |
| 114 | +- Admin: `admin` / `admin123` |
| 115 | +- RabbitMQ UI: values from `.env.example` (`nexus` / `nexus_dev_password`) |
| 116 | + |
| 117 | +For local non-Docker backend work, set `JWT_SECRET`, `SPRING_DATASOURCE_PASSWORD`, and `SPRING_RABBITMQ_PASSWORD` before running `mvn spring-boot:run`. |
| 118 | + |
| 119 | +## API Highlights |
| 120 | + |
| 121 | +- `POST /api/orders` with `Idempotency-Key` |
| 122 | +- `GET /api/orders?status=VALIDATED&size=10&sort=createdAt,desc` |
| 123 | +- `GET /api/orders/{id}` |
| 124 | +- `POST /api/orders/{id}/payments` |
| 125 | +- `PATCH /api/orders/{id}/status` |
| 126 | +- `GET /api/products` |
| 127 | +- `GET /api/admin/inventory` |
| 128 | +- `POST /api/admin/products` |
| 129 | + |
| 130 | +## Testing |
| 131 | + |
| 132 | +```bash |
| 133 | +cd server |
| 134 | +mvn test |
| 135 | + |
| 136 | +cd ../client |
| 137 | +npm ci |
| 138 | +npm run lint |
| 139 | +npm run build |
123 | 140 | ``` |
124 | 141 |
|
125 | | -### CI (GitHub Actions) |
126 | | -- Workflow: `.github/workflows/ci.yml` |
127 | | -- Backend: `mvn verify` in `server` |
128 | | -- Frontend: `npm ci && npm run build` in `client` |
| 142 | +Current automated coverage includes: |
| 143 | + |
| 144 | +- Order state transitions, idempotency, stock reservation, payment commit/release |
| 145 | +- Transactional outbox enqueueing and relay publish/retry behavior |
| 146 | +- Product service validation paths |
| 147 | +- Controller validation, authentication requirement, payment/status endpoints |
| 148 | +- JPA optimistic locking |
| 149 | +- PostgreSQL Testcontainers persistence check when Docker is available |
| 150 | + |
| 151 | +On the current machine, the Testcontainers test skipped because Docker Desktop was not exposing a usable Docker engine. The rest of the backend suite passed. |
| 152 | + |
| 153 | +## CI/CD |
| 154 | + |
| 155 | +`.github/workflows/ci.yml` runs: |
| 156 | + |
| 157 | +- Backend: `mvn -B verify` |
| 158 | +- Frontend: `npm ci`, `npm run build`, `npm run lint` |
| 159 | + |
| 160 | +No README badges are included because badges should only be added after the workflow runs successfully on the repository remote. |
| 161 | + |
| 162 | +## Screenshots |
129 | 163 |
|
130 | | -> **Note:** Use JDK 17 for local Maven builds. Using newer JDKs (e.g., 21/23) can trigger `TypeTag :: UNKNOWN` javac errors with Lombok; Docker Compose already uses the correct JDK. |
| 164 | +Screenshots are not committed yet. Recommended captures after starting Docker Compose: |
131 | 165 |
|
132 | | -### API Documentation (Swagger) |
133 | | -1) Start services, then open [http://localhost:8080/swagger-ui.html](http://localhost:8080/swagger-ui.html) |
134 | | -2) Click **Authorize** and paste your JWT (no `Bearer ` prefix needed) |
135 | | -3) Try any endpoint directly from the UI |
| 166 | +- Login page with demo credential note |
| 167 | +- User dashboard showing product availability and order history |
| 168 | +- Operations page showing inventory reservations and order transitions |
| 169 | +- Swagger UI with authorized JWT |
| 170 | +- RabbitMQ queue view for `nexusflow.order-events` |
136 | 171 |
|
137 | | -### Validation & Errors |
138 | | -- All request DTOs are validated (`@Valid`, `@NotNull`, `@Min`, `@NotBlank`) |
139 | | -- Errors return a structured payload: `timestamp`, `status`, `error`, `message`, `path`, and `validationErrors` |
140 | | -- Concurrency conflicts return HTTP 409 with guidance to retry |
| 172 | +## Interview Talking Points |
141 | 173 |
|
142 | | -### Monitoring |
143 | | -- Health: `/actuator/health` |
144 | | -- Metrics: `/actuator/metrics` |
145 | | -- Prometheus scrape: `/actuator/prometheus` |
| 174 | +- Why order transitions belong in an application service/state machine instead of controllers |
| 175 | +- How optimistic locking protects stock updates under concurrent orders |
| 176 | +- Why stock is reserved at validation and committed at payment capture |
| 177 | +- How idempotency protects retries from duplicate order creation |
| 178 | +- How the transactional outbox prevents order commits from depending on RabbitMQ availability |
| 179 | +- How RBAC is split between endpoint security and business rules |
| 180 | +- How structured errors and correlation IDs improve debugging |
146 | 181 |
|
147 | | -### Default Roles |
148 | | -- **User**: Register a new account via the UI. |
149 | | -- **Admin**: Manually update the database `users` table to promote a user to `ROLE_ADMIN` to access inventory management features. |
| 182 | +## What I Would Improve Next |
150 | 183 |
|
151 | | -## 🧪 Future Improvements |
152 | | -- **Integration Testing**: Add Testcontainers to simulate real PostgreSQL/RabbitMQ instances during CI/CD. |
153 | | -- **Observability**: Integrate Prometheus and Grafana for metrics monitoring. |
| 184 | +- Add RabbitMQ Testcontainers coverage |
| 185 | +- Add a replay/admin endpoint for dead outbox events |
| 186 | +- Add refresh tokens and token revocation for a production auth model |
| 187 | +- Add Playwright UI tests and committed screenshots |
| 188 | +- Add Prometheus/Grafana dashboards for the custom order metrics |
0 commit comments