A production-ready, full-stack e-commerce marketplace scaffold that connects buyers and sellers. Somiishop provides a fully configured, runnable starting point β complete with authentication, payments, product management, and order tracking β so you can focus on building your marketplace, not the boilerplate.
- β¨ Features
- ποΈ Tech Stack
- π Project Structure
- π§ Prerequisites
- π Quick Start with Docker
- π» Local Development
- βοΈ Environment Variables
- π API Endpoints
- ποΈ Database Schema
- π οΈ Development Commands
- π§ͺ Testing
- π Troubleshooting
- πΊοΈ Implementation Roadmap
- π License
- Stripe Connect Payments β PaymentIntent creation with platform commission tracking (default 5%) and webhook handling [1]
- Multi-role User System β
BUYER,SELLER, andADMINroles with JWT-based access control [2] - Product Catalog β Full CRUD with category/price filtering, keyword search, and paginated browsing [3]
- Order Lifecycle Management β Statuses:
PENDINGβPAIDβSHIPPEDβDELIVEREDβCOMPLETED/CANCELLED, with stock validation on creation [4] - Email Notifications via SendGrid β Verification, password reset, order confirmation, and seller notifications [5]
- JWT Authentication with Token Refresh β 15-minute access tokens and 7-day refresh tokens [6]
- Persistent Shopping Cart β Cart state stored in browser
localStorage - Review & Rating System β Verified-purchase tracking with a one-review-per-product-per-user constraint [7]
- Docker Compose β One-command local environment with PostgreSQL, backend, and frontend services wired together [8]
- Database Migrations β Flyway-managed schema versioning with auto-migration at startup [9]
| Technology | Version | Purpose |
|---|---|---|
| Java | 21 | Runtime [10] |
| Spring Boot | 3.2.2 | Application framework [11] |
| Maven | 3.9+ | Build tool [12] |
| Spring Data JPA | β | ORM & repository layer |
| Spring Security | β | Authentication & authorization |
| Spring Mail | β | Email dispatch |
| PostgreSQL | 16 | Primary database [13] |
| Flyway | 10.8.1 | Database migrations [14] |
| JJWT | 0.12.3 | JWT creation & validation, HS512 algorithm [14] |
| BCrypt | β | Password hashing (strength 12) [15] |
| Stripe Java SDK | 24.14.0 | Payment processing [14] |
| AWS SDK for S3 | 2.21.26 | File/image storage [14] |
| Lombok | 1.18.32 | Boilerplate reduction |
| Testcontainers | 1.19.3 | Integration testing [14] |
| Technology | Version | Purpose |
|---|---|---|
| Angular | 17.3.0 | UI framework [16] |
| TypeScript | 5.4.2 (strict) | Language [17] |
| RxJS | 7.8.0 | Reactive programming [18] |
| @stripe/stripe-js | 2.4.0 | Stripe.js integration [18] |
| Karma + Jasmine | 6.4.0 + 5.1.0 | Unit testing [19] |
| Technology | Version | Purpose |
|---|---|---|
| Docker & Docker Compose | 3.8 | Container orchestration [20] |
| PostgreSQL (Alpine) | 16 | Containerized database [13] |
somiishop-scaffold/
βββ backend/
β βββ src/main/java/com/somiishop/
β β βββ config/ # Security, CORS, BCrypt configuration
β β βββ controller/ # REST API endpoints (Auth, Product, Order, Payment, Category)
β β βββ dto/ # Data Transfer Objects
β β βββ entity/ # JPA entities (User, Product, Order, Payment, Review)
β β βββ repository/ # Spring Data repositories
β β βββ service/ # Business logic (JWT, Stripe, Cart, Email)
β β βββ security/ # JWT authentication filter
β β βββ exception/ # Global error handling
β β βββ SomiishopApplication.java
β βββ src/main/resources/
β β βββ application.yml # Main configuration
β β βββ application-local.yml
β β βββ db/migration/ # Flyway SQL migrations
β βββ pom.xml
β βββ Dockerfile
βββ frontend/
β βββ src/app/
β β βββ core/
β β β βββ services/ # Auth, Cart, Order, Payment, Product services
β β β βββ guards/ # AuthGuard, RoleGuard for route protection
β β β βββ interceptors/ # JWT token attachment, 401 handling
β β βββ features/ # Feature modules (auth, checkout, home)
β β βββ app.component.ts
β βββ src/environments/ # Environment configurations
β βββ package.json
β βββ angular.json
β βββ Dockerfile
βββ docker-compose.yml
βββ NEXT_STEPS.md # 10-phase implementation roadmap
βββ README.md
The backend follows a layered architecture [21]: controllers handle HTTP concerns, services own business logic, and repositories provide data access. The frontend organizes code into core/ (singleton services, guards, interceptors) and features/ (route-scoped modules) [22].
Before getting started, ensure the following are installed:
| Requirement | Version | Notes |
|---|---|---|
| Java JDK | 21 | Required for backend [10] |
| Node.js + npm | 18+ | Required for frontend [23] |
| Docker & Docker Compose | Latest | Required for containerized setup |
| PostgreSQL | 16 | Only needed for non-Docker local dev |
| Maven | 3.9+ | Only needed for non-Docker local dev [12] |
The fastest way to run the full stack locally. All services β PostgreSQL, backend, and frontend β start with a single command. [8]
git clone https://github.com/your-org/somiishop-scaffold.git
cd somiishop-scaffoldCreate a .env file in the project root. The required and optional variables are listed below (see Environment Variables for the full reference).
# Required
STRIPE_API_KEY=sk_test_...
STRIPE_WEBHOOK_SECRET=whsec_...
JWT_SECRET=<your-256-bit-secret>
# Database (defaults shown)
DB_NAME=somiishop
DB_USER=somiishop
DB_PASSWORD=somiishop_dev
# Optional β AWS S3 image storage
AWS_S3_BUCKET=somiishop-uploads
AWS_REGION=us-east-1Generating a JWT secret: Run
openssl rand -base64 64to generate a suitable 512-bit secret.
docker-compose up --buildDocker Compose starts PostgreSQL first (with a health check), waits for it to be ready, then starts the backend, and finally the frontend. [24]
| Service | URL |
|---|---|
| Frontend | http://localhost:4200 |
| Backend API | http://localhost:8080 |
| PostgreSQL | localhost:5432 |
curl http://localhost:8080/actuator/health
# Expected: {"status":"UP"}docker-compose down # Stop containers
docker-compose down -v # Stop and remove volumes (clears database)For faster iteration cycles without Docker, run the backend and frontend directly on your machine.
macOS (Homebrew):
brew services start postgresql@16
createdb somiishop
createuser somiishopStart the backend:
cd backend
mvn spring-boot:runFlyway will automatically apply all pending migrations on startup. [9] The API will be available at http://localhost:8080.
cd frontend
npm install
ng serveThe Angular dev server starts at http://localhost:4200 with hot-reload enabled. [25] The frontend is configured to connect to the backend at http://localhost:8080/api/v1. [26]
All backend configuration is driven by environment variables, with sensible defaults defined in application.yml. [27]
| Variable | Example | Description |
|---|---|---|
STRIPE_API_KEY |
sk_test_... |
Stripe secret key for payment processing [28] |
STRIPE_WEBHOOK_SECRET |
whsec_... |
Stripe webhook endpoint secret for signature verification [28] |
JWT_SECRET |
<256-bit string> |
HS512 signing secret for JWT tokens (minimum 256 bits) [6] |
| Variable | Default | Description |
|---|---|---|
DB_NAME |
somiishop |
PostgreSQL database name [9] |
DB_USER |
somiishop |
PostgreSQL username [9] |
DB_PASSWORD |
somiishop_dev |
PostgreSQL password [9] |
DB_HOST |
localhost |
PostgreSQL host (use db inside Docker) [29] |
DB_PORT |
5432 |
PostgreSQL port [9] |
| Variable | Default | Description |
|---|---|---|
MAIL_HOST |
smtp.sendgrid.net |
SMTP host [5] |
MAIL_PORT |
587 |
SMTP port with STARTTLS [5] |
MAIL_USERNAME |
β | SMTP username (typically apikey for SendGrid) |
MAIL_PASSWORD |
β | SendGrid API key used as SMTP password |
| Variable | Default | Description |
|---|---|---|
AWS_S3_BUCKET |
somiishop-uploads |
S3 bucket for product image storage [28] |
AWS_REGION |
us-east-1 |
AWS region [28] |
AWS_ACCESS_KEY_ID |
β | AWS access key ID |
AWS_SECRET_ACCESS_KEY |
β | AWS secret access key |
| Variable | Default | Description |
|---|---|---|
CORS_ALLOWED_ORIGINS |
http://localhost:4200 |
Comma-separated allowed CORS origins [28] |
FRONTEND_URL |
http://localhost:4200 |
Frontend base URL for email links [28] |
| Setting | Value | Description |
|---|---|---|
| Access token expiry | 900,000 ms (15 min) | Short-lived JWT for API access [6] |
| Refresh token expiry | 604,800,000 ms (7 days) | Long-lived token for access token renewal [6] |
| Max file upload size | 10 MB | Per-file and per-request limit [30] |
All endpoints are prefixed with /api/v1. Authentication uses the Authorization: Bearer <token> header. [31]
Access levels used in the tables below:
- π Public β No authentication required
- π Authenticated β Valid JWT required
- πͺ Seller β Must be the owning seller (verified in service layer)
- π Admin β Admin role required
Base path: /api/v1/auth [32]
| Method | Endpoint | Description | Access | Notes |
|---|---|---|---|---|
POST |
/register |
Register a new user | π Public | Auto-assigns BUYER role; sends verification email [33] |
POST |
/login |
Login and receive tokens | π Public | Returns accessToken + refreshToken [34] |
POST |
/refresh |
Exchange refresh token for new access token | π Public | Body: { "refreshToken": "..." } [35] |
POST |
/logout |
Logout | π Authenticated | Stateless β client clears tokens from localStorage [36] |
Register request body:
{
"email": "user@example.com",
"password": "minimum8chars"
}Login / Register response:
{
"userId": "uuid",
"email": "user@example.com",
"accessToken": "eyJ...",
"refreshToken": "eyJ...",
"tokenType": "Bearer",
"expiresIn": 900,
"roles": ["BUYER"]
}Base path: /api/v1/products [3]
| Method | Endpoint | Description | Access |
|---|---|---|---|
GET |
/ |
Browse products with pagination, search, and filters | π Public [37] |
GET |
/{id} |
Get product details by ID | π Public [38] |
GET |
/category/{categoryId} |
Browse products by category | π Public [39] |
GET |
/seller/{sellerId} |
List a seller's products | π Public [40] |
POST |
/ |
Create a new product listing | πͺ Seller [41] |
PUT |
/{id} |
Update a product listing | πͺ Seller [42] |
DELETE |
/{id} |
Delete a product listing | πͺ Seller [43] |
GET / query parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
page |
int |
0 |
Page number |
size |
int |
20 |
Results per page |
keyword |
string |
β | Search term |
categoryId |
UUID |
β | Filter by category |
minPrice |
decimal |
0 |
Minimum price filter |
maxPrice |
decimal |
1000000 |
Maximum price filter |
sortBy |
string |
createdAt |
Sort field |
Base path: /api/v1/orders [44]
| Method | Endpoint | Description | Access |
|---|---|---|---|
POST |
/ |
Create an order with stock validation | π Authenticated [4] |
GET |
/{id} |
Get order details | π Authenticated [45] |
GET |
/ |
Buyer's paginated order history | π Authenticated [46] |
GET |
/seller |
Seller's incoming orders | πͺ Seller [47] |
PUT |
/{id}/status |
Update order status | πͺ Seller [48] |
DELETE |
/{id} |
Cancel a pending order (restores stock) | π Authenticated (buyer) [49] |
Order statuses: PENDING β PAID β SHIPPED β DELIVERED β COMPLETED Β· CANCELLED [50]
Status update request body:
{
"status": "SHIPPED"
}Base path: /api/v1/payments [51]
| Method | Endpoint | Description | Access |
|---|---|---|---|
POST |
/intent |
Create a Stripe PaymentIntent for an order | π Authenticated [51] |
POST |
/webhook |
Stripe webhook receiver | π Public (Stripe-only) [52] |
Create PaymentIntent request:
{
"orderId": "uuid"
}PaymentIntent response:
{
"intentId": "pi_...",
"clientSecret": "pi_..._secret_...",
"amount": 4999,
"currency": "usd",
"status": "requires_payment_method"
}The webhook endpoint handles payment_intent.succeeded events, updates the payment record, transitions the order status to PAID, and sends confirmation emails. [53]
Base path: /api/v1/categories [54]
| Method | Endpoint | Description | Access |
|---|---|---|---|
GET |
/ |
List all categories | π Public [55] |
GET |
/{id} |
Get category by ID | π Public |
POST |
/ |
Create a category (auto-generates slug) | π Admin [56] |
PUT |
/{id} |
Update category name and slug | π Admin [57] |
DELETE |
/{id} |
Delete a category | π Admin [58] |
Create/update request body:
{
"name": "Electronics"
}Slugs are auto-generated from the name (lowercase, spaces β hyphens). [59]
The full schema is created by a single Flyway migration: V1__initial_schema.sql. [7]
| Table | Description |
|---|---|
users |
User accounts with email, hashed password, and role |
user_roles |
Join table for user role assignments |
profiles |
Extended user profile data |
categories |
Product categories with auto-generated slugs |
products |
Product listings linked to sellers and categories |
orders |
Orders with status lifecycle and timestamps |
order_items |
Line items within each order |
payments |
Stripe payment records linked to orders |
reviews |
Ratings with one-review-per-product-per-user constraint [7] |
addresses |
Shipping and billing addresses |
platform_settings |
Global settings (e.g., commission rate β default 5%) [1] |
audit_logs |
Activity audit trail indexed by actor and timestamp |
Performance indexes are created on high-traffic query paths [60]:
productsβseller_id,category_id,is_active,price,created_atordersβbuyer_id,status,created_atpaymentsβorder_id,statusreviewsβproduct_id,reviewer_id
HikariCP is configured with a maximum of 10 connections and a minimum of 5 idle connections, with a 30-second connection timeout. [9]
cd backend
# Run the application (hot-reload via Spring DevTools)
mvn spring-boot:run
# Build a production JAR (skipping tests)
mvn clean package -DskipTests
# Run unit and integration tests
mvn test
# Reset and re-run all Flyway migrations
mvn flyway:clean flyway:migrateThe backend Dockerfile uses a two-stage build: Maven 3.9 + Eclipse Temurin 21 (Alpine) for building, and Eclipse Temurin 21 JRE (Alpine) for the runtime image. [61]
cd frontend
# Install dependencies
npm install
# Start the dev server (http://localhost:4200, with hot-reload)
npm start
# Production build (output to dist/somiishop-frontend)
npm run build
# Run unit tests (Karma + Jasmine)
npm test
# Run end-to-end tests
npm run e2e
# Lint the codebase
npm run lintThe frontend Dockerfile uses node:18-alpine and starts the Angular dev server bound to 0.0.0.0 with 2000 ms polling for file changes inside Docker. [62] The production build targets dist/somiishop-frontend. [63]
Integration tests use Testcontainers to spin up a real PostgreSQL 16 instance, ensuring migrations and queries run against an authentic database. [14]
cd backend
mvn testUnit tests use Karma 6.4.0 as the test runner and Jasmine 5.1.0 as the assertion framework, with code coverage via karma-coverage. [19]
cd frontend
npm test # Run unit tests once
npm run e2e # Run end-to-end testsTypeScript strict mode is enforced across the entire frontend codebase, including strictInjectionParameters and strictTemplates for Angular-specific checks. [17]
# Check if PostgreSQL is running and accepting connections
pg_isready -h localhost -p 5432
# Check Docker container health
docker-compose ps
docker logs somiishop-dbEnsure DB_HOST is set to db (the Docker service name) when running inside Docker, or localhost for local development. [29]
# Find and kill the process using port 8080
lsof -i :8080
kill -9 <PID>
# Or for the frontend port
lsof -i :4200
kill -9 <PID>If the database schema gets into an inconsistent state, reset and re-run all migrations:
cd backend
mvn flyway:clean flyway:migrate
β οΈ flyway:cleandrops all database objects. Never run this against a production database.
Verify the API_BASE_URL environment variable is set correctly [26]:
- Docker:
http://localhost:8080/api/v1 - Local dev: Ensure the backend is running on port 8080 and CORS allows
http://localhost:4200[28]
Use the Stripe CLI to forward events to your local server:
stripe listen --forward-to localhost:8080/api/v1/payments/webhookThe CLI will print a webhook signing secret β use that value as STRIPE_WEBHOOK_SECRET.
This scaffold ships with all infrastructure wired up. The NEXT_STEPS.md file contains a detailed 10-phase implementation guide to build out a production marketplace. [64]
What's already done [65]
- β Project structure (Spring Boot backend, Angular frontend, Docker)
- β PostgreSQL schema with Flyway migrations (all tables created)
- β
Core entities:
User,Profile,Product,Category,Order,OrderItem,Payment,Review,Address - β Security scaffolding: CORS, BCrypt, session management, JWT filter
- β
Frontend services:
AuthService,AuthGuard,RoleGuard
| Phase | Focus Area | Estimated Effort |
|---|---|---|
| 1 | Complete Authentication (JWT service, AuthController, EmailService) | 1β2 days |
| 2 | Product Catalog (ProductService, ProductController, S3 integration) | 2β3 days |
| 3 | Shopping Cart (CartService, CartController) | 1β2 days |
| 4 | Checkout & Stripe Connect (StripeService, webhooks) | 3β4 days |
| 5 | Orders & Delivery Tracking (OrderService, OrderController) | 2β3 days |
| 6 | Reviews (ReviewService with verified-purchase check) | 1β2 days |
| 7 | Seller Onboarding (Stripe Connect account creation) | 2 days |
| 8 | Admin Dashboard (KPIs, user management) | 3β4 days |
| 9 | Profile & UI Polish (responsive design, ProfileController) | 2β3 days |
| 10 | Testing & Deployment (unit, integration, E2E, CI/CD) | 2β3 days |
Post-MVP enhancements [66]
Real-time notifications (WebSocket) Β· Automated seller payouts Β· Seller analytics Β· Shipping API integration Β· Product variants Β· Wish lists Β· Advanced search (Elasticsearch) Β· Mobile app Β· Live chat Β· Loyalty programme
This project is licensed under the MIT License. See the LICENSE file for details.