Skip to content

Commit 11b904c

Browse files
committed
Document CI and container setup
1 parent 6251143 commit 11b904c

5 files changed

Lines changed: 269 additions & 280 deletions

File tree

.env.example

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
POSTGRES_DB=nexusdb
2+
POSTGRES_USER=nexus
3+
POSTGRES_PASSWORD=nexus_dev_password
4+
POSTGRES_PORT=5432
5+
6+
RABBITMQ_USERNAME=nexus
7+
RABBITMQ_PASSWORD=nexus_dev_password
8+
RABBITMQ_PORT=5672
9+
RABBITMQ_MANAGEMENT_PORT=15672
10+
11+
BACKEND_PORT=8080
12+
FRONTEND_PORT=5173
13+
VITE_API_URL=http://localhost:8080/api
14+
APP_CORS_ALLOWED_ORIGINS=http://localhost:5173,http://localhost:3000
15+
APP_OUTBOX_ENABLED=true
16+
APP_OUTBOX_PUBLISH_DELAY_MS=5000
17+
APP_OUTBOX_BATCH_SIZE=25
18+
APP_OUTBOX_MAX_ATTEMPTS=8
19+
20+
JWT_SECRET=replace-with-at-least-32-characters-for-local-dev
21+
SEED_ENABLED=true

.github/workflows/ci.yml

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ jobs:
2727

2828
- name: Build and test
2929
working-directory: server
30+
env:
31+
JWT_SECRET: ci-test-secret-key-must-be-at-least-32-characters
32+
SPRING_DATASOURCE_PASSWORD: ci-postgres-password
33+
SPRING_RABBITMQ_PASSWORD: ci-rabbitmq-password
3034
run: mvn -B verify
3135

3236
frontend:
@@ -39,7 +43,7 @@ jobs:
3943
- name: Setup Node
4044
uses: actions/setup-node@v4
4145
with:
42-
node-version: '18'
46+
node-version: '22'
4347
cache: 'npm'
4448
cache-dependency-path: client/package-lock.json
4549

@@ -50,3 +54,7 @@ jobs:
5054
- name: Build
5155
working-directory: client
5256
run: npm run build
57+
58+
- name: Lint
59+
working-directory: client
60+
run: npm run lint

README.md

Lines changed: 156 additions & 121 deletions
Original file line numberDiff line numberDiff line change
@@ -1,153 +1,188 @@
1-
# NexusFlow: Enterprise Order Processor
1+
# NexusFlow Enterprise Order Processor
22

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.
44

5-
## 🌟 Key Features
5+
## Problem It Solves
66

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.
118

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
1610

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
2016

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
2418

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:
2920

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
3327

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+
```
4141

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
4643

47-
### Architecture Diagram
4844
```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
5459
```
5560

56-
## 🛠 Tech Stack
61+
## Key Features
5762

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
6579

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
7381

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
7588

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`.
8392

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
8794

88-
### Deployment (Recommended)
89-
Run the entire stack with a single command:
95+
Prerequisites: Docker Desktop.
9096

9197
```bash
92-
docker-compose up --build
98+
docker compose --env-file .env.example up --build
9399
```
94100

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
123140
```
124141

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
129163

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:
131165

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`
136171

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
141173

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
146181

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
150183

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

Comments
 (0)