SEAPEDIA is a full-stack marketplace built for the COMPFEST 18 Software Engineering Academy challenge. It supports guest browsing, multi-role authentication, seller store management, buyer checkout, driver delivery, and admin monitoring in one monorepo.
Backend authorization is driven by the user's selected active role, so one account can hold several roles but only acts with the one it has activated.
- Public marketplace: guests can browse products, stores, product details, and public application reviews.
- Authentication: registration, login, JWT authentication, and active-role selection.
- Multi-role users: one account can own multiple roles, but protected workflows authorize against the selected
activeRole. - Seller workflow: create stores, manage products, process incoming orders, and view income reports.
- Buyer workflow: wallet top-up, transaction history, addresses, single-store cart, checkout, order history, and spending reports.
- Checkout rules: subtotal, one voucher or promo code, PPN 12%, delivery fee, stock updates, and wallet payment.
- Driver workflow: discover available delivery jobs, claim jobs, complete deliveries, and view earnings.
- Admin workflow: monitoring, voucher/promo management, user creation, simulated time advance, and overdue order processing.
- Order lifecycle:
SEDANG_DIKEMAS,MENUNGGU_PENGIRIM,SEDANG_DIKIRIM,PESANAN_SELESAI, andDIKEMBALIKAN.
- Monorepo: npm workspaces
- Frontend: React, Vite, TypeScript, Tailwind CSS, lucide-react
- Backend: NestJS, TypeScript, JWT, class-validator
- Database: PostgreSQL 15 through Docker Compose
- ORM: Prisma
- Testing: Jest and Supertest for the API
.
|-- apps
| |-- api # NestJS API, Prisma schema, migrations, seed data
| `-- web # React/Vite single-page application
|-- docs # Requirements, API reference, and testing guide
|-- docker-compose.yaml # Local PostgreSQL service
|-- package.json # Root workspace scripts
`-- README.md
- Node.js and npm
- Docker Desktop or another Docker Compose-compatible runtime
- Git
This is the fastest way to run the whole stack. It starts PostgreSQL, the API, and the web app, applies migrations, and seeds demo data automatically.
-
Create the environment file.
Copy-Item .env.example .env -
Build and start everything.
docker compose up --build -
Open the web app at
http://localhost:5173. The API is athttp://localhost:3000and Swagger UI athttp://localhost:3000/docs.
The database is seeded on startup with the demo accounts, catalog, discounts, and a sample in-delivery order, so every dashboard has data on first load. Log in with any account from Demo Accounts.
-
Install dependencies.
npm install
-
Create the root environment file.
Copy-Item .env.example .env -
Start PostgreSQL.
npm run db:up
-
Run Prisma migration, generate the client, and seed demo data.
npm run prisma:migrate npm run prisma:generate npm run db:seed
-
Start the API and web app in separate terminals.
npm run dev:api
npm run dev:web
By default, the API runs on http://localhost:3000. The Vite dev server prints the web URL in the terminal, usually http://localhost:5173.
The root .env is used by Docker Compose and the API's local database connection.
POSTGRES_USER=seapedia_admin
POSTGRES_PASSWORD=seapedia_secret
POSTGRES_DB=seapedia_db
DATABASE_URL="postgresql://seapedia_admin:seapedia_secret@localhost:5432/seapedia_db?schema=public"
PORT=3000
JWT_SECRET=change-me-in-local-development
WEB_ORIGIN=http://localhost:5173WEB_ORIGIN is the comma-separated list of browser origins allowed to call the API (CORS). If it is not set, the API allows http://localhost:5173, the default Vite dev server origin.
The web app reads VITE_API_URL. If it is not set, it defaults to http://localhost:3000.
All seeded demo accounts use password password123.
| Role | |
|---|---|
| Admin | admin@seapedia.test |
| Seller | seller@seapedia.test |
| Buyer | buyer@seapedia.test |
| Driver | driver@seapedia.test |
| Multi-role | multi@seapedia.test |
After login, choose an active role before using private dashboards or role-protected API endpoints.
| Command | Purpose |
|---|---|
npm run db:up |
Start the PostgreSQL container |
npm run db:down |
Stop Docker Compose services |
npm run db:logs |
Stream PostgreSQL logs |
npm run dev:api |
Start the NestJS API in watch mode |
npm run dev:web |
Start the Vite web app |
npm run build:api |
Build the API |
npm run build:web |
Build the web app |
npm run test:api |
Run API unit tests |
npm run lint:api |
Lint and fix API files |
npm run lint:web |
Lint the web app |
npm run prisma:migrate |
Apply Prisma migrations in development |
npm run prisma:generate |
Generate Prisma Client |
npm run db:seed |
Seed demo users, products, discounts, and related data |
npm run setup:check |
Validate Docker Compose configuration |
POST /auth/register,POST /auth/login,POST /auth/select-role,POST /auth/roles,GET /auth/meGET /products,GET /stores,GET /reviews,POST /reviews- Seller endpoints for stores, products, order processing, and income reports
- Buyer endpoints for wallet, addresses, cart, checkout, orders, and spending reports
- Driver endpoints for available jobs, claimed jobs, completion, and earnings
- Admin endpoints for monitoring, vouchers, promos, users, simulated time, and overdue processing
Interactive Swagger UI is served at GET /docs (OpenAPI JSON at /docs-json) while the API is running. See docs/seapedia-api-reference.md for the offline endpoint reference.
- Protected role APIs authorize against the JWT's selected
activeRole. - A registered account starts as a Buyer and can self-add the
SELLERand/orDRIVERrole from the account panel (POST /auth/roles), then select it to activate.ADMINis not self-grantable and is created only through seed data or the protected admin user endpoint. - Guests can browse catalog data and create public application reviews.
- A cart can contain products from one store only.
- Checkout calculates
subtotal - discount + PPN 12% + delivery fee. - One checkout discount code is accepted and resolved as either a voucher or promo.
- Seller order processing creates the delivery job.
- A driver can claim an available delivery job only once.
- Overdue processing is idempotent: it refunds the buyer wallet, restores stock, marks delivery returned, writes status history, and records the processing log.
- SQL injection: all database access goes through Prisma's parameterized query API; there are no raw string-concatenated SQL queries.
- XSS: user-generated content (application reviews and comments) is rendered as text through React, which escapes it by default. The app does not use
dangerouslySetInnerHTML. - Input validation: a global
ValidationPipe(whitelist,forbidNonWhitelisted,transform) plusclass-validatorDTOs validate and reject unexpected or malformed fields (email, phone, rating, quantity, price, stock, discount values) with clear error messages. - Session behavior: authentication uses JWT bearer tokens signed with
JWT_SECRETand expiring after1d. Logout clears the token on the client, and protected requests are rejected once the token expires. - Role-based access control: protected endpoints are guarded server-side by
JwtAuthGuardand anActiveRoleGuardthat authorizes against the token's selectedactiveRole, not the full role list. Ownership checks prevent acting on another user's store, order, or job. Admin-only endpoints are not reachable by non-admin roles. - Security headers:
helmetsets standard hardening headers (X-Content-Type-Options,X-Frame-Options, HSTS, etc.). Its Content-Security-Policy is disabled so the self-hosted Swagger UI at/docsrenders correctly. - Rate limiting:
@nestjs/throttlerapplies a global limit of 100 requests/minute per IP, tightened to 5 requests/minute on the public write endpointsPOST /auth/login,POST /auth/register, andPOST /reviewsto blunt brute-force and spam. Exceeding a limit returns429 Too Many Requests.
Run the API tests with:
npm run test:apiFor manual acceptance testing:
- Browse products, stores, and reviews as a guest.
- Submit a public review.
- Login as seller, select
SELLER, create a store/product, then confirm it appears in the public catalog. - Login as buyer, select
BUYER, top up wallet, add an address, add a product to cart, and checkout withHEMAT10KorPROMO10. - Login as seller again and process the new order.
- Login as driver, select
DRIVER, claim the available job, then complete it. - Login as admin, select
ADMIN, inspect monitoring, create discounts, advance simulated time, and process overdue orders.
See docs/seapedia-testing-guide.md for the full testing guide.