A full-stack e-commerce application with a Spring Boot backend and React frontend. Demonstrates JWT authentication with guest-to-authenticated cart merge, Stripe Checkout integration, Redis-backed caching, Flyway migrations, and a production-ready single-application deploy model.
- Browse products and filter by category.
- Add items to cart as a guest (no login required).
- Register an account or log in.
- Watch your guest cart items merge into your authenticated cart.
- Proceed to Stripe Checkout.
- View order history with payment status.
- Backend: Java 21, Spring Boot 3.4, Spring Security, PostgreSQL, Redis, Flyway, Stripe API
- Frontend: React 19, TypeScript, Vite, Tailwind CSS, React Router
- Infrastructure: Docker Compose, GitHub Actions CI, JaCoCo coverage
- Java 21
- Docker (optional, for Postgres + Redis in non-local profile)
- Node.js (for frontend hot-reload dev mode only)
- Stripe account + Stripe CLI (optional, for checkout/webhook testing)
Build everything into one Spring Boot JAR (backend + frontend static bundle):
./mvnw clean package -DskipTests
java -jar target/store-0.0.1-SNAPSHOT.jar --spring.profiles.active=localVisit http://localhost:8080.
Terminal 1 — backend:
./mvnw spring-boot:run -Dspring-boot.run.profiles=localTerminal 2 — frontend:
cd frontend
npm install
cp .env.example .env
npm run devVisit http://localhost:5173.
Primary demo is the frontend UI. For API-level verification:
- Swagger UI:
http://localhost:8080/swagger-ui/index.html - OpenAPI JSON:
http://localhost:8080/v3/api-docs
Postman remains available as a secondary option:
StoreAPIs.postman_collection.jsonStore.local.postman_environment.json
Webhook endpoint:
POST /checkout/webhook
- Install Stripe CLI:
https://stripe.com/docs/stripe-cli - Authenticate once:
stripe login- Forward webhooks to local backend:
stripe listen --forward-to localhost:8080/checkout/webhook- Copy CLI signing secret (
whsec_...) into.env:
STRIPE_WEBHOOK_SECRET_KEY
- Set Stripe secret API key in
.env:
STRIPE_SECRET_KEY=sk_test_...
Optional webhook trigger for a specific order:
stripe trigger checkout.session.completed \
--override "checkout_session:client_reference_id=<orderId>" \
--override "checkout_session:metadata[order_id]=<orderId>".env is loaded via:
spring.config.import=optional:file:.env[.properties]
Common settings (example.env):
DB_URL / DB_USER / DB_PASSWORDREDIS_HOST / REDIS_PORT / REDIS_PASSWORDSPRING_CACHE_TYPE(redisdefault, orsimple)WEBSITE_URL(Stripe success/cancel URL base)JWT_SECRET / ACCESS_EXPIRATION / REFRESH_EXPIRATION / GUEST_EXPIRATIONSTRIPE_SECRET_KEY / STRIPE_WEBHOOK_SECRET_KEYCOOKIE_SECURE(setfalsefor localhost HTTP cookie testing)
- OWASP Top 10 Hardening — Documented protections against each OWASP Top 10 category
- Rate limiting, security headers, input validation, auth hardening, and security event logging
Measured locally; results vary by machine and background load.
- GET
/productsp95 latency:- Cold: 11.435 ms
- Warm: 5.037 ms
- Improvement: 55.95% faster p95
- Throughput (
ab -n 500 -c 20 /products):- 1,995.12 req/s
- 95th percentile latency: 23 ms
- Coverage (JaCoCo):
- 39.67% line coverage (288 / 726)
- Scope:
- 22 endpoints (GET 8, POST 7, PUT 3, DELETE 4)
- 8 entities (
Address,Cart,CartItem,Category,Order,OrderItem,Product,User)
./mvnw testCoverage report:
./mvnw test jacoco:reportOpen:
target/site/jacoco/index.html