Add rental system: listings, bookings, payments, payouts, reviews
Full rental marketplace with 6 categories (apartment, house, car, motorcycle, bicycle, ebike). Booking workflow: create → confirm → pay → active → complete → payout. Landlord dashboard, admin moderation, availability calendar, Stripe Connect payouts. 14 QA bugs found and fixed including validator schemas, API response types, HTTP methods. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
287
docs/README.md
287
docs/README.md
@@ -1,81 +1,214 @@
|
||||
# Color Wheel Palette Generator
|
||||
# Marketplace
|
||||
|
||||
An interactive color palette generator built with React, TypeScript, and Tailwind CSS v4. Pick a base color on a color wheel, choose a harmony type, adjust tint/shade, and export palettes in multiple formats.
|
||||
|
||||
## Features
|
||||
|
||||
- **Interactive Color Wheel** — Canvas-based HSL wheel with drag-to-select hue and saturation. Touch support for mobile.
|
||||
- **7 Harmony Types** — Complementary, Split-Complementary, Analogous, Triadic, Tetradic, Square, Monochromatic.
|
||||
- **Tint & Shade Slider** — Adjust lightness in real-time.
|
||||
- **Color Input** — Enter HEX values directly, view RGB/HSL, adjust via RGB sliders.
|
||||
- **Click-to-Copy** — Copy any color value (HEX, RGB, HSL) to clipboard.
|
||||
- **Export** — CSS variables, JSON, Tailwind config snippet, or PNG image.
|
||||
- **Dark / Light Theme** — Toggle between dark and light modes.
|
||||
- **Responsive** — Mobile-first layout with horizontal scroll palette on small screens.
|
||||
|
||||
## Setup
|
||||
|
||||
```bash
|
||||
npm install
|
||||
npm run dev
|
||||
```
|
||||
|
||||
Open `http://localhost:5173` in your browser.
|
||||
|
||||
## Build
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
npm run preview
|
||||
```
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
src/
|
||||
├── components/ # UI components
|
||||
│ ├── ColorWheel/ # Canvas-based color wheel with pointer events
|
||||
│ ├── PaletteDisplay/ # Generated swatch grid
|
||||
│ ├── HarmonySelector/ # Dropdown for harmony type
|
||||
│ ├── ColorInput/ # HEX/RGB/HSL inputs and sliders
|
||||
│ ├── TintShadeSlider/ # Lightness adjustment
|
||||
│ ├── ExportPanel/ # CSS/JSON/Tailwind/PNG export
|
||||
│ ├── Header/ # App header with theme toggle
|
||||
│ └── MobileNav/ # Bottom sheet navigation for mobile
|
||||
├── hooks/
|
||||
│ ├── useColorWheel.ts # Wheel interaction (drag, position calculation)
|
||||
│ └── useColorHarmony.ts # Harmony palette generation
|
||||
├── utils/
|
||||
│ ├── colorConversions.ts # HEX <-> RGB <-> HSL converters
|
||||
│ └── harmonies.ts # Harmony algorithms
|
||||
├── App.tsx # Main layout
|
||||
├── main.tsx # Entry point
|
||||
└── index.css # Tailwind directives + theme variables
|
||||
```
|
||||
|
||||
## Harmony Algorithms
|
||||
|
||||
| Type | Colors Generated |
|
||||
|---|---|
|
||||
| Complementary | Base + 180° |
|
||||
| Split-Complementary | Base, +150°, +210° |
|
||||
| Analogous | -30°, Base, +30° |
|
||||
| Triadic | Base, +120°, +240° |
|
||||
| Tetradic | Base, +90°, +180°, +270° |
|
||||
| Square | Base, +90°, +180°, +270° |
|
||||
| Monochromatic | Same hue, varied S/L |
|
||||
|
||||
## MCP Integration
|
||||
|
||||
The project includes MCP server configuration in `.claude/settings.json`:
|
||||
|
||||
- **Figma MCP** — Connect to Figma to read design files and create new frames.
|
||||
- **Chrome DevTools MCP** — Debug the running app, inspect elements, and validate layouts.
|
||||
A full-stack online marketplace and rental platform where users can buy, sell, and rent items ranging from electronics and furniture to apartments, cars, and bicycles. The platform includes real-time chat, an offer/negotiation system, Stripe-powered payments, and a multi-role admin panel with content moderation.
|
||||
|
||||
## Tech Stack
|
||||
|
||||
- React 19 + TypeScript
|
||||
- Vite
|
||||
- Tailwind CSS v4
|
||||
- HTML5 Canvas API
|
||||
- Clipboard API
|
||||
| Layer | Technology |
|
||||
|----------------|------------------------------------------------------|
|
||||
| **Client** | React 19, TypeScript, Tailwind CSS 4, Vite 6 |
|
||||
| **Routing** | React Router 7 |
|
||||
| **Server** | Express 4, TypeScript, tsx (dev runner) |
|
||||
| **Database** | PostgreSQL 17 (Docker), Prisma ORM 6 |
|
||||
| **Auth** | JWT (access + refresh tokens), bcryptjs |
|
||||
| **Payments** | Stripe (PaymentIntents, Connect, Webhooks) |
|
||||
| **Real-time** | Socket.io 4 (notifications, chat) |
|
||||
| **File Upload**| Multer (local storage) |
|
||||
| **Validation** | Zod |
|
||||
| **Charts** | Recharts 3 (admin dashboard) |
|
||||
| **Icons** | Lucide React |
|
||||
|
||||
## Features
|
||||
|
||||
- **Listings** -- Create, browse, search, and filter buy/sell listings across categories (Electronics, Furniture, Clothing, Vehicles, etc.)
|
||||
- **Offers & Negotiation** -- Make offers, counter, accept, or decline with real-time notifications
|
||||
- **Rentals** -- Full rental system for apartments, houses, cars, motorcycles, bicycles, and e-bikes with daily/monthly pricing, booking management, deposits, and cancellation policies
|
||||
- **Chat** -- Real-time messaging between buyers/sellers and tenants/landlords via Socket.io
|
||||
- **Payments** -- Stripe integration for listing fees, commissions, rental bookings, deposits, and landlord payouts via Stripe Connect
|
||||
- **Subscriptions & Promotions** -- Tiered seller subscriptions (Basic, Pro, Business) and listing promotion/boosting
|
||||
- **Notifications** -- Real-time in-app notifications for offers, messages, bookings, payouts, and moderation actions
|
||||
- **Moderation** -- Content reporting, review queue, user banning, and moderation logs
|
||||
- **Admin Panel** -- Dashboard with analytics, user management, listing management, and moderation tools
|
||||
- **Auth & Roles** -- JWT authentication with four roles: `USER`, `MODERATOR`, `ADMIN`, `SUPER_ADMIN`
|
||||
- **Location** -- Google Maps autocomplete for listing and rental locations
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- **Node.js** >= 18
|
||||
- **npm** >= 9 (uses npm workspaces)
|
||||
- **Docker** (for PostgreSQL)
|
||||
|
||||
## Getting Started
|
||||
|
||||
### 1. Start the Database
|
||||
|
||||
If the Docker container already exists:
|
||||
|
||||
```bash
|
||||
docker start marketplace-postgres
|
||||
```
|
||||
|
||||
If you need to create it from scratch:
|
||||
|
||||
```bash
|
||||
docker run -d \
|
||||
--name marketplace-postgres \
|
||||
-e POSTGRES_USER=marketplace \
|
||||
-e POSTGRES_PASSWORD=marketplace_dev \
|
||||
-e POSTGRES_DB=marketplace \
|
||||
-p 5432:5432 \
|
||||
-v marketplace-pgdata:/var/lib/postgresql/data \
|
||||
--restart unless-stopped \
|
||||
postgres:17-alpine
|
||||
```
|
||||
|
||||
Verify it is running:
|
||||
|
||||
```bash
|
||||
docker ps -f name=marketplace-postgres
|
||||
```
|
||||
|
||||
### 2. Install Dependencies
|
||||
|
||||
From the project root:
|
||||
|
||||
```bash
|
||||
npm install
|
||||
```
|
||||
|
||||
This installs dependencies for both the `client` and `server` workspaces.
|
||||
|
||||
### 3. Configure Environment Variables
|
||||
|
||||
Create `server/.env`:
|
||||
|
||||
```env
|
||||
DATABASE_URL=postgresql://marketplace:marketplace_dev@localhost:5432/marketplace
|
||||
JWT_SECRET=your-secret-key
|
||||
JWT_REFRESH_SECRET=your-refresh-secret-key
|
||||
STRIPE_SECRET_KEY=sk_test_...
|
||||
STRIPE_PUBLISHABLE_KEY=pk_test_...
|
||||
STRIPE_WEBHOOK_SECRET=whsec_...
|
||||
GOOGLE_MAPS_API_KEY=your-google-maps-key
|
||||
CLIENT_URL=http://localhost:5173
|
||||
UPLOAD_DIR=./uploads
|
||||
PORT=3000
|
||||
```
|
||||
|
||||
For local development, only `DATABASE_URL` is strictly required. Stripe keys are optional (payment features will be disabled). The server provides sensible defaults for all other values.
|
||||
|
||||
### 4. Set Up the Database Schema
|
||||
|
||||
```bash
|
||||
cd server
|
||||
npx prisma db push
|
||||
```
|
||||
|
||||
Or use migrations:
|
||||
|
||||
```bash
|
||||
cd server
|
||||
npx prisma migrate dev
|
||||
```
|
||||
|
||||
### 5. Seed the Database (Optional)
|
||||
|
||||
```bash
|
||||
cd server
|
||||
npx tsx prisma/seed.ts
|
||||
```
|
||||
|
||||
### 6. Run the Application
|
||||
|
||||
Start both client and server simultaneously:
|
||||
|
||||
```bash
|
||||
npm run dev
|
||||
```
|
||||
|
||||
Or run them separately:
|
||||
|
||||
```bash
|
||||
npm run dev:server # Express API on http://localhost:3000
|
||||
npm run dev:client # React app on http://localhost:5173
|
||||
```
|
||||
|
||||
## Seed Data
|
||||
|
||||
After seeding, the following test users are available (all use password `password123`):
|
||||
|
||||
| Email | Name |
|
||||
|----------------------------|----------------|
|
||||
| alice.chen@example.com | Alice Chen |
|
||||
| bob.smith@example.com | Bob Smith |
|
||||
| carol.jones@example.com | Carol Jones |
|
||||
| david.wilson@example.com | David Wilson |
|
||||
| eva.martinez@example.com | Eva Martinez |
|
||||
|
||||
## Project Structure
|
||||
|
||||
```
|
||||
marketplace/
|
||||
├── package.json # Root workspace config
|
||||
├── CLAUDE.md # Dev notes (DB setup, commands)
|
||||
├── docs/ # Documentation
|
||||
│ ├── README.md # This file
|
||||
│ └── architecture.md # Architecture overview
|
||||
├── client/ # React frontend
|
||||
│ ├── package.json
|
||||
│ └── src/
|
||||
│ ├── api/ # API client functions
|
||||
│ ├── components/ # Reusable UI components
|
||||
│ ├── context/ # React context providers
|
||||
│ ├── pages/ # Route page components
|
||||
│ ├── router.tsx # Route definitions
|
||||
│ ├── types/ # TypeScript type definitions
|
||||
│ ├── utils/ # Utility functions
|
||||
│ ├── App.tsx # App root component
|
||||
│ └── main.tsx # Entry point
|
||||
└── server/ # Express backend
|
||||
├── package.json
|
||||
├── prisma/
|
||||
│ ├── schema.prisma # Database schema
|
||||
│ └── seed.ts # Seed script
|
||||
└── src/
|
||||
├── config/ # Environment config
|
||||
├── middleware/ # Auth, upload, validation, error handling
|
||||
├── routes/ # API route handlers
|
||||
│ └── admin/ # Admin-specific routes
|
||||
├── socket/ # Socket.io setup and handlers
|
||||
├── utils/ # Shared utilities
|
||||
├── validators/ # Zod validation schemas
|
||||
└── index.ts # Server entry point
|
||||
```
|
||||
|
||||
## Environment Variables Reference
|
||||
|
||||
| Variable | Required | Default | Description |
|
||||
|---------------------------|----------|----------------------------------|------------------------------------|
|
||||
| `DATABASE_URL` | Yes | localhost connection string | PostgreSQL connection URL |
|
||||
| `PORT` | No | `3000` | Server port |
|
||||
| `JWT_SECRET` | No* | Dev fallback | Access token signing secret |
|
||||
| `JWT_REFRESH_SECRET` | No* | Dev fallback | Refresh token signing secret |
|
||||
| `CLIENT_URL` | No | `http://localhost:5173` | CORS allowed origin |
|
||||
| `UPLOAD_DIR` | No | `./uploads` | File upload directory |
|
||||
| `STRIPE_SECRET_KEY` | No | Empty (payments disabled) | Stripe secret key |
|
||||
| `STRIPE_PUBLISHABLE_KEY` | No | Empty (payments disabled) | Stripe publishable key |
|
||||
| `STRIPE_WEBHOOK_SECRET` | No | Empty | Stripe webhook signing secret |
|
||||
| `GOOGLE_MAPS_API_KEY` | No | Dev key | Google Maps API key |
|
||||
|
||||
*Must be set to secure values in production.
|
||||
|
||||
## Useful Commands
|
||||
|
||||
| Command | Description |
|
||||
|---------------------------|------------------------------------------|
|
||||
| `npm run dev` | Start client + server concurrently |
|
||||
| `npm run dev:client` | Start React dev server (port 5173) |
|
||||
| `npm run dev:server` | Start Express dev server (port 3000) |
|
||||
| `npm run build` | Build client and server for production |
|
||||
| `npm run lint` | Lint client code |
|
||||
| `npx prisma studio` | Open Prisma Studio (DB browser) |
|
||||
| `npx prisma db push` | Push schema changes to database |
|
||||
| `npx prisma migrate dev` | Create and apply a migration |
|
||||
| `npx tsx prisma/seed.ts` | Seed the database |
|
||||
|
||||
332
docs/architecture.md
Normal file
332
docs/architecture.md
Normal file
@@ -0,0 +1,332 @@
|
||||
# Architecture
|
||||
|
||||
## High-Level Overview
|
||||
|
||||
```
|
||||
┌──────────────────────────────────────────────────────────────┐
|
||||
│ Client (React) │
|
||||
│ http://localhost:5173 (Vite) │
|
||||
│ │
|
||||
│ ┌──────────┐ ┌──────────┐ ┌───────────┐ ┌────────────┐ │
|
||||
│ │ Pages │ │Components│ │ Context │ │ API Layer │ │
|
||||
│ └──────────┘ └──────────┘ └───────────┘ └─────┬──────┘ │
|
||||
│ │ │
|
||||
└────────────────────────────────────────────────────┼─────────┘
|
||||
REST API (HTTP) │ WebSocket │
|
||||
│ (Socket.io) │
|
||||
┌──────────────────────────────────┼─────────────────┼─────────┐
|
||||
│ Server (Express) │ │
|
||||
│ http://localhost:3000 │ │
|
||||
│ │ │
|
||||
│ ┌───────────┐ ┌────────────┐ ┌──────────────┐ │ │
|
||||
│ │ Middleware │ │ Routes │ │ Socket.io │◄─┘ │
|
||||
│ │ (auth, │ │ (REST API) │ │ (real-time) │ │
|
||||
│ │ upload, │ └─────┬──────┘ └──────┬───────┘ │
|
||||
│ │ validate)│ │ │ │
|
||||
│ └───────────┘ │ │ │
|
||||
│ ┌────┴────────────────┴──────┐ │
|
||||
│ │ Prisma ORM │ │
|
||||
│ └────────────┬───────────────┘ │
|
||||
│ │ │
|
||||
└───────────────────────────────┼──────────────────────────────┘
|
||||
│
|
||||
┌───────────────────────────────┼──────────────────────────────┐
|
||||
│ PostgreSQL 17 (Docker) │
|
||||
│ marketplace-postgres container │
|
||||
│ Volume: marketplace-pgdata │
|
||||
└──────────────────────────────────────────────────────────────┘
|
||||
|
||||
External Services:
|
||||
┌─────────┐ ┌──────────────┐
|
||||
│ Stripe │ │ Google Maps │
|
||||
│ (pay) │ │ (location) │
|
||||
└─────────┘ └──────────────┘
|
||||
```
|
||||
|
||||
## Client-Server Communication
|
||||
|
||||
### REST API
|
||||
|
||||
The client communicates with the server via a JSON REST API. All endpoints are prefixed with `/api/`.
|
||||
|
||||
| Prefix | Purpose |
|
||||
|-----------------------|----------------------------------------------|
|
||||
| `/api/auth` | Registration, login, token refresh, logout |
|
||||
| `/api/users` | User profiles, settings, privacy |
|
||||
| `/api/listings` | CRUD for buy/sell listings, search, favorites|
|
||||
| `/api/offers` | Create, counter, accept, decline offers |
|
||||
| `/api/chat` | Conversations and message history |
|
||||
| `/api/notifications` | Fetch and mark notifications as read |
|
||||
| `/api/payments` | Stripe payment intents, webhooks |
|
||||
| `/api/location` | Google Maps autocomplete proxy |
|
||||
| `/api/reports` | Content/user reporting |
|
||||
| `/api/subscriptions` | Seller subscription management |
|
||||
| `/api/promotions` | Listing promotion/boost |
|
||||
| `/api/admin` | Admin dashboard, user/listing management |
|
||||
| `/api/rentals` | Rental listing CRUD and search |
|
||||
| `/api/bookings` | Booking lifecycle management |
|
||||
| `/api/rental-payments`| Rental payment processing and webhooks |
|
||||
| `/api/payouts` | Landlord payout management |
|
||||
| `/api/rental-reviews` | Tenant/landlord reviews |
|
||||
| `/api/health` | Health check endpoint |
|
||||
|
||||
### Socket.io (WebSocket)
|
||||
|
||||
Socket.io provides the real-time communication layer. The server creates a Socket.io instance attached to the same HTTP server as Express.
|
||||
|
||||
**Events flow:**
|
||||
- The client connects with an auth token after login
|
||||
- The server authenticates the socket connection and associates it with a user
|
||||
- Real-time events are emitted for: new messages, notifications (offers, bookings, moderation), typing indicators, and online status
|
||||
|
||||
## Database Layer
|
||||
|
||||
### Prisma ORM
|
||||
|
||||
The database schema is defined in `server/prisma/schema.prisma`. Prisma generates a type-safe client used throughout the server routes.
|
||||
|
||||
**Key models:**
|
||||
|
||||
| Model | Purpose |
|
||||
|-------------------|--------------------------------------------------|
|
||||
| `User` | Accounts with roles, privacy settings, landlord status |
|
||||
| `Session` | JWT refresh token sessions |
|
||||
| `Listing` | Buy/sell items with category, condition, price |
|
||||
| `ListingImage` | Image attachments for listings |
|
||||
| `Offer` | Price negotiation between buyer and seller |
|
||||
| `Conversation` | Chat threads between two users |
|
||||
| `Message` | Individual chat messages |
|
||||
| `Favorite` | User bookmarks on listings |
|
||||
| `Notification` | In-app notifications (19 distinct types) |
|
||||
| `Payment` | Payment records (8 payment types) |
|
||||
| `Report` | Content/user reports for moderation |
|
||||
| `Subscription` | Seller tier subscriptions |
|
||||
| `PromotedListing` | Boosted listing placements |
|
||||
| `ModerationLog` | Audit trail for moderation actions |
|
||||
| `BlockedUser` | User blocking relationships |
|
||||
| `RentalListing` | Rental items (apartments, cars, bikes, etc.) |
|
||||
| `Booking` | Rental booking with status lifecycle |
|
||||
| `RentalReview` | Reviews for completed rentals |
|
||||
| `Payout` | Landlord payout tracking |
|
||||
|
||||
### Enums
|
||||
|
||||
The schema uses PostgreSQL enums extensively for type safety:
|
||||
|
||||
- **User roles:** `USER`, `MODERATOR`, `ADMIN`, `SUPER_ADMIN`
|
||||
- **Listing categories:** `ELECTRONICS`, `FURNITURE`, `CLOTHING`, `HOME_GARDEN`, `SPORTS`, `BOOKS`, `GAMES`, `VEHICLES`, `OTHER`
|
||||
- **Rental categories:** `APARTMENT`, `HOUSE`, `CAR`, `MOTORCYCLE`, `BICYCLE`, `EBIKE`
|
||||
- **Booking status:** `PENDING` -> `CONFIRMED` -> `ACTIVE` -> `COMPLETED` (or `CANCELLED_*` / `REJECTED` / `EXPIRED`)
|
||||
- **Cancellation policy:** `FLEXIBLE`, `MODERATE`, `STRICT`
|
||||
|
||||
## Authentication Flow
|
||||
|
||||
The application uses JWT-based authentication with access and refresh tokens.
|
||||
|
||||
```
|
||||
┌────────┐ ┌────────┐
|
||||
│ Client │ │ Server │
|
||||
└───┬────┘ └───┬────┘
|
||||
│ POST /api/auth/login │
|
||||
│ { email, password } │
|
||||
├──────────────────────────────────────►│
|
||||
│ │ Verify password (bcryptjs)
|
||||
│ │ Generate access token (short-lived)
|
||||
│ │ Generate refresh token (long-lived)
|
||||
│ │ Store session in DB
|
||||
│ { accessToken, user } │
|
||||
│ Set-Cookie: refreshToken (httpOnly) │
|
||||
│◄──────────────────────────────────────┤
|
||||
│ │
|
||||
│ GET /api/listings │
|
||||
│ Authorization: Bearer <accessToken> │
|
||||
├──────────────────────────────────────►│
|
||||
│ │ auth middleware verifies JWT
|
||||
│ │ checkBanned middleware
|
||||
│ { listings: [...] } │
|
||||
│◄──────────────────────────────────────┤
|
||||
│ │
|
||||
│ POST /api/auth/refresh │
|
||||
│ Cookie: refreshToken │
|
||||
├──────────────────────────────────────►│
|
||||
│ │ Validate refresh token
|
||||
│ │ Issue new access token
|
||||
│ { accessToken } │
|
||||
│◄──────────────────────────────────────┤
|
||||
```
|
||||
|
||||
### Middleware Chain
|
||||
|
||||
Requests pass through several middleware layers:
|
||||
|
||||
1. **`helmet`** -- Security headers
|
||||
2. **`cors`** -- Restricts origins to `CLIENT_URL`
|
||||
3. **`cookieParser`** -- Parses refresh token cookies
|
||||
4. **`express-rate-limit`** -- Rate limits auth endpoints (20 requests / 15 min)
|
||||
5. **`auth`** -- Verifies JWT access token, attaches user to request
|
||||
6. **`checkBanned`** -- Blocks banned users
|
||||
7. **`requireRole`** -- Role-based access control (e.g., admin-only routes)
|
||||
8. **`upload`** -- Multer file upload handling
|
||||
9. **`validate`** -- Zod schema validation for request bodies
|
||||
|
||||
## Payment Flow
|
||||
|
||||
### Marketplace Payments (Listings)
|
||||
|
||||
Stripe PaymentIntents are used for buy/sell transactions:
|
||||
|
||||
```
|
||||
┌────────┐ ┌────────┐ ┌────────┐
|
||||
│ Buyer │ │ Server │ │ Stripe │
|
||||
└───┬────┘ └───┬────┘ └───┬────┘
|
||||
│ Create PI │ │
|
||||
├───────────────►│ POST /api/ │
|
||||
│ │ payments │
|
||||
│ ├───────────────►│ stripe.paymentIntents.create()
|
||||
│ │ clientSecret │
|
||||
│ │◄───────────────┤
|
||||
│ clientSecret │ │
|
||||
│◄───────────────┤ │
|
||||
│ │ │
|
||||
│ Confirm (Stripe.js) │
|
||||
├────────────────────────────────►│
|
||||
│ │ │
|
||||
│ │ Webhook event │
|
||||
│ │◄───────────────┤ payment_intent.succeeded
|
||||
│ │ Update DB │
|
||||
│ │ Notify seller │
|
||||
│ │ │
|
||||
```
|
||||
|
||||
### Rental Payments
|
||||
|
||||
Rental bookings follow a similar flow with additional handling for:
|
||||
|
||||
- **Security deposits** -- Held and refunded after completion
|
||||
- **Landlord payouts** -- Via Stripe Connect (`stripeAccountId` on User model)
|
||||
- **Commissions** -- Platform fee deducted from rental payments
|
||||
- **Separate webhook endpoint** -- `/api/rental-payments/webhook`
|
||||
|
||||
### Payment Types
|
||||
|
||||
The system tracks eight distinct payment types:
|
||||
|
||||
| Type | Description |
|
||||
|------------------------|-------------------------------------------|
|
||||
| `LISTING_FEE` | Fee to publish a listing |
|
||||
| `COMMISSION` | Platform commission on sales |
|
||||
| `PROMOTION` | Listing boost/promotion fee |
|
||||
| `SUBSCRIPTION` | Seller subscription payment |
|
||||
| `RENTAL_BOOKING` | Tenant rental payment |
|
||||
| `RENTAL_COMMISSION` | Platform fee on rentals |
|
||||
| `RENTAL_DEPOSIT` | Security deposit hold |
|
||||
| `RENTAL_DEPOSIT_REFUND`| Deposit refund after completion |
|
||||
| `RENTAL_PAYOUT` | Payment to landlord via Connect |
|
||||
|
||||
## File Uploads
|
||||
|
||||
File uploads are handled by **Multer** with local disk storage.
|
||||
|
||||
- **Configuration:** `server/src/middleware/upload.ts`
|
||||
- **Storage directory:** Configurable via `UPLOAD_DIR` env var (default: `./uploads`)
|
||||
- **Serving:** Static files served at `/uploads/*` via `express.static`
|
||||
- **Usage:** Listing images, rental listing photos, user avatars
|
||||
|
||||
Files are stored on the local filesystem. In production, this should be replaced with cloud storage (e.g., S3, Cloudflare R2).
|
||||
|
||||
## Real-Time Communication
|
||||
|
||||
Socket.io is configured in `server/src/socket/index.ts` and attached to the HTTP server alongside Express.
|
||||
|
||||
### Connection Flow
|
||||
|
||||
1. Client establishes WebSocket connection after successful login
|
||||
2. Server authenticates the connection using the JWT token
|
||||
3. User is registered as "online" and associated with their socket ID
|
||||
|
||||
### Event Types
|
||||
|
||||
| Category | Events |
|
||||
|-----------------|--------------------------------------------------|
|
||||
| **Chat** | New message, typing indicator, read receipts |
|
||||
| **Notifications**| New offer, offer response, booking updates, payout status, moderation actions |
|
||||
| **Presence** | User online/offline status |
|
||||
|
||||
### Architecture
|
||||
|
||||
```
|
||||
Client A ──WebSocket──┐
|
||||
├──► Socket.io Server ──► Emit to Client B
|
||||
Client B ──WebSocket──┘ │
|
||||
│
|
||||
┌─────┴─────┐
|
||||
│ Express │
|
||||
│ routes │
|
||||
│ can emit │
|
||||
│ via io │
|
||||
└───────────┘
|
||||
```
|
||||
|
||||
Express routes access the Socket.io instance via `app.get('io')` to emit events from REST handlers (e.g., sending a notification when an offer is created via the REST API).
|
||||
|
||||
## Security
|
||||
|
||||
| Concern | Implementation |
|
||||
|----------------------|---------------------------------------------------|
|
||||
| HTTP headers | Helmet (XSS, clickjacking, MIME sniffing) |
|
||||
| CORS | Restricted to `CLIENT_URL` |
|
||||
| Rate limiting | 20 req/15 min on `/api/auth/login` and `/register`|
|
||||
| Input validation | Zod schemas on all mutation endpoints |
|
||||
| Password hashing | bcryptjs |
|
||||
| Token storage | Refresh token in httpOnly cookie |
|
||||
| Role-based access | `requireRole` middleware for admin/mod routes |
|
||||
| User banning | `checkBanned` middleware on protected routes |
|
||||
| Webhook verification | Stripe webhook signature verification |
|
||||
|
||||
## Deployment Considerations
|
||||
|
||||
### Database
|
||||
|
||||
- Use a managed PostgreSQL service (e.g., AWS RDS, Supabase, Neon) in production
|
||||
- Run `npx prisma migrate deploy` to apply migrations
|
||||
- The Docker setup is intended for local development only
|
||||
|
||||
### File Storage
|
||||
|
||||
- Replace local Multer storage with S3-compatible storage (AWS S3, Cloudflare R2, MinIO)
|
||||
- Update the upload middleware and static file serving accordingly
|
||||
|
||||
### Environment
|
||||
|
||||
- Set strong, unique values for `JWT_SECRET` and `JWT_REFRESH_SECRET`
|
||||
- Use production Stripe keys and configure webhook endpoints
|
||||
- Set `CLIENT_URL` to the deployed frontend URL
|
||||
|
||||
### Scaling
|
||||
|
||||
- **Horizontal scaling:** Socket.io requires a Redis adapter (`@socket.io/redis-adapter`) for multi-instance deployments
|
||||
- **Static assets:** Serve the built React app via a CDN or reverse proxy (Nginx, Cloudflare)
|
||||
- **API:** The Express server is stateless (JWT-based auth) and can be scaled horizontally behind a load balancer
|
||||
|
||||
### Recommended Production Stack
|
||||
|
||||
```
|
||||
┌───────────┐
|
||||
│ CDN / │
|
||||
│ Nginx │
|
||||
└─────┬─────┘
|
||||
│
|
||||
┌───────────┴───────────┐
|
||||
│ │
|
||||
┌────────▼─────┐ ┌─────────▼────────┐
|
||||
│ React Static │ │ Express API x N │
|
||||
│ (built) │ │ (load balanced) │
|
||||
└──────────────┘ └────────┬──────────┘
|
||||
│
|
||||
┌───────────────┼───────────────┐
|
||||
│ │ │
|
||||
┌──────▼──┐ ┌──────▼──┐ ┌───────▼──┐
|
||||
│PostgreSQL│ │ Redis │ │ S3 / R2 │
|
||||
│(managed) │ │(sockets)│ │ (files) │
|
||||
└──────────┘ └─────────┘ └──────────┘
|
||||
```
|
||||
Reference in New Issue
Block a user