| Metric | Value |
|---|---|
| Total SLOC | 8,786 |
| Source Files | 58 |
| .js | 3,796 |
| .tsx | 2,838 |
| .md | 1,336 |
| .ts | 614 |
| .json | 105 |
A simplified Etsy-like platform demonstrating seller marketplace dynamics, search relevance, personalization, and handmade/vintage product discovery. This educational project focuses on building a multi-seller e-commerce platform with emphasis on unique product discovery.
- Shop setup and branding
- Product listings
- Inventory management
- Order fulfillment
- Category browsing
- Full-text search with Elasticsearch
- Synonym-enhanced search for handmade items
- Trending and popular items
- Favorite shops and items
- View history tracking
- Similar product recommendations
- Shopping cart (multi-seller)
- Checkout with orders split by seller
- Order tracking per seller
- Reviews and favorites
- Frontend: TypeScript, Vite, React 19, TanStack Router, Zustand, Tailwind CSS
- Backend: Node.js, Express
- Database: PostgreSQL
- Cache/Sessions: Redis
- Search: Elasticsearch
- Node.js 18+
- Docker and Docker Compose
- npm or yarn
# Start PostgreSQL, Redis, and Elasticsearch
docker-compose up -d
# Wait for services to be healthy (especially Elasticsearch)
docker-compose pscd backend
# Install dependencies
npm install
# Copy environment file
cp .env.example .env
# Run database migrations
npm run migrate
# Seed with sample data
npm run seed
# Start the backend server
npm run devThe backend runs on http://localhost:3000
cd frontend
# Install dependencies
npm install
# Start the frontend dev server
npm run devThe frontend runs on http://localhost:5173
After running the seed script, these accounts are available:
| Password | Role | |
|---|---|---|
| buyer@example.com | password123 | Buyer |
| alice@example.com | password123 | Seller (Alice's Handmade Jewelry) |
| bob@example.com | password123 | Seller (Bob's Woodwork Studio) |
| carol@example.com | password123 | Seller (Carol's Vintage Finds) |
| admin@example.com | admin123 | Admin |
POST /api/auth/register- Register new userPOST /api/auth/login- LoginPOST /api/auth/logout- LogoutGET /api/auth/me- Get current user
GET /api/shops- List shopsGET /api/shops/:id- Get shop by IDGET /api/shops/slug/:slug- Get shop by slugPOST /api/shops- Create shop (auth required)PUT /api/shops/:id- Update shop (owner only)GET /api/shops/:id/products- Get shop productsGET /api/shops/:id/orders- Get shop orders (owner only)GET /api/shops/:id/stats- Get shop stats (owner only)
GET /api/products- List productsGET /api/products/search- Search products (Elasticsearch)GET /api/products/trending- Get trending productsGET /api/products/:id- Get product detailsPOST /api/products- Create product (shop owner)PUT /api/products/:id- Update product (shop owner)DELETE /api/products/:id- Delete product (shop owner)
GET /api/cart- Get cart (grouped by shop)POST /api/cart/items- Add to cartPUT /api/cart/items/:id- Update quantityDELETE /api/cart/items/:id- Remove itemDELETE /api/cart- Clear cart
GET /api/orders- Get user's ordersGET /api/orders/:id- Get order detailsPOST /api/orders/checkout- Create order(s)PUT /api/orders/:id/status- Update status (seller)
GET /api/favorites- Get favoritesPOST /api/favorites- Add favoriteDELETE /api/favorites/:type/:id- Remove favoriteGET /api/favorites/check/:type/:id- Check if favorited
GET /api/reviews/product/:id- Get product reviewsGET /api/reviews/shop/:id- Get shop reviewsPOST /api/reviews- Create review (must have purchased)PUT /api/reviews/:id- Update reviewDELETE /api/reviews/:id- Delete review
GET /api/categories- List categoriesGET /api/categories/:id/products- Get products in category
etsy/
├── docker-compose.yml # PostgreSQL, Redis, Elasticsearch
├── backend/
│ ├── src/
│ │ ├── db/ # Database connection and migrations
│ │ ├── routes/ # Express route handlers
│ │ ├── services/ # Redis, Elasticsearch clients
│ │ ├── middleware/ # Auth middleware
│ │ ├── config.js # Environment config
│ │ └── index.js # Express app entry
│ └── uploads/ # Product images
├── frontend/
│ ├── src/
│ │ ├── components/ # React components
│ │ ├── routes/ # TanStack Router pages
│ │ ├── stores/ # Zustand stores
│ │ ├── services/ # API client
│ │ └── types/ # TypeScript types
│ └── index.html
├── architecture.md # System design documentation
├── claude.md # Development notes
└── README.md # This file
For testing load balancing and distributed scenarios:
# Terminal 1
npm run dev:server1 # Port 3001
# Terminal 2
npm run dev:server2 # Port 3002
# Terminal 3
npm run dev:server3 # Port 3003Cart items are grouped by shop, and checkout creates separate orders per seller with independent fulfillment tracking.
Elasticsearch with synonym filters handles varied terminology (handmade, handcrafted, artisan) and fuzzy matching for typos.
Products often have quantity=1. Short cart reservations (15 min) prevent overselling unique items.
Recommendations based on favorites and view history, with trending products for cold-start users.
See architecture.md for detailed system design documentation.
See claude.md for development insights and design decisions.
- Etsy Code as Craft - Etsy's official engineering blog with marketplace insights
- Search Ranking at Etsy - Context-aware search and ranking
- Personalization at Scale - Etsy's approach to product recommendations
- Elasticsearch Synonyms Guide - Handling variant terminology in search
- Relevance Tuning for E-Commerce - Balancing relevance and business rules
- Two-Sided Marketplace Design - Andreessen Horowitz insights on marketplace dynamics
- Building Etsy's Activity Feed - Architecture for activity feeds and notifications
- Search Quality at Pinterest - Related approaches to discovery-based commerce