World Vibe Web
The distributed app store for vibe-coded projects. Browse, discover, and install open-source apps from across GitHub.
翻譯準備中
尚未偵測到更新。GitHub 發布版本後會顯示在這裡。
個人 GitHub 帳號下公開儲存庫的擁有者可以登入並驗證所有權,自行管理介紹,無需管理員核准。
登入並產生驗證檔案,在 30 分鐘內將其提交至此儲存庫的預設分支。其他分支或分叉儲存庫中的檔案無效。然後在下方檢查檔案,即可無需管理員核准直接管理專案。請保留檔案以維持管理權限。
如需登入,將前往登入頁面。登入後請回到此處,再次點擊所選的驗證按鈕。
在專案資料夾中執行 /nomorevibe verify,即可驗證所有權並自行管理介紹。
一分鐘完成驗證Dress rental marketplace platform
翻譯準備中
取自儲存庫 README
正在載入完整 README。 以下為已儲存的摘錄。
A full-stack dress rental marketplace. Dress owners list items for rent; renters browse an approved public catalog, check real-time availability, and book by date range and size. Built end-to-end (schema, API, auth, business logic, UI) as an independent project.
UI is in Hebrew with full RTL support.檢視完整 README ↗A full-stack dress rental marketplace. Dress owners list items for rent; renters browse an approved public catalog, check real-time availability, and book by date range and size. Built end-to-end (schema, API, auth, business logic, UI) as an independent project.
Stack: NestJS · Prisma · PostgreSQL · Next.js (App Router) · React · TypeScript · Tailwind CSS
UI is in Hebrew with full RTL support.
Catalog
page/limit, with total match count)/catalog-pdf) via the browser's own print-to-PDF, listing every approved dress with a real clickable link to its page — for anyone who can browse the images offline but can't reach the live site to click through directlyrouter.back() real history pop, paired with an in-memory cache of the last fetched results (and view state, on the catalog) so the grid re-renders at full height on the same page instantly instead of flashing an empty loading skeleton first (which would otherwise cut the browser's own scroll restoration short)Marketing
/promo.html (apps/web/public/promo.html) — a self-contained static file (own HTML/CSS/JS, no dependency on the rest of the app or any external account) meant to be shared directly for real distribution. Payment-by-credit-card is explicitly marked "coming soon" there, since it isn't live yet.app/dress/[id]/page.tsx is a real Server Component with a generateMetadata that fetches server-side (crawlers never run the client-side fetch the page content itself uses) against a dedicated single-dress endpoint (GET /dresses/approved/:id) rather than the paginated catalog listlocalStorage) so it doesn't nag a returning visitorListings
pendingDetails, pendingAction: ADD/REMOVE on sizes/photos) rather than mutating the live rowBookings
SERIALIZABLE transaction with automatic retry, so two simultaneous requests for the last unit of a size can't both succeedINTERESTED holds that never convert to a confirmed rental auto-expire after 7 days (scheduled job, also runs once on startup so a restart doesn't wait for the next midnight run) and release their date/size back into the calendarDressAvailabilityBlock, folded into the same public availability feed the calendar readsINTERESTED booking herself (hard-deleted — nothing meaningful to preserve), instead of only being able to wait out the 7-day auto-expiry or ask the owner to do it; cancelling an already-RENTED booking still requires the owner, since that's a real confirmed rentalRENTED booking's end date has passed, the renter can leave a 1-5 star rating and an optional comment from "הבקשות שלי" (one review per booking, enforced by a unique constraint). A dress's averageRating/reviewCount are denormalized onto the Dress row itself (recomputed via aggregate whenever a review is created), so the rating shown on every catalog card, and the reviews list on the dress's own page, never costs a join or a live aggregate on a normal page viewRenter-facing UI
Favorite join table (one row per user/dress pair, idempotent add/remove); a "מועדפים" page lists everything favorited, with the same card and unfavorite-to-remove interactionOwner-facing UI
Notifications
INTERESTED hold is about to auto-expire[dev-only] console log used before — nothing breaks, emails just aren't delivered to real inboxes yetNotificationsService.send() choke point — the eventual domain-verified from address change, or any future provider swap, touches one method, not each trigger siteAuth & authorization
USER / ADMIN) — the API refuses to start without a JWT_SECRET env var (no insecure hardcoded fallback)/auth route, and on feedback/review submission and dress photo upload — blocks brute-force login/credential-stuffing, registration/reset-email spam, and repeated hits on the CPU-heavy photo-processing pipeline?redirect= target, resolved through the same URL parser the browser's own navigation uses and only trusted when it still resolves to this origin (rather than a naive string-prefix check, which a crafted value using stripped-by-the-parser control characters could bypass) — a logged-out visitor who tries to express interest in a dress lands back on that exact dress page after signing in, instead of the homepage; the login↔register cross-link carries the same param through so switching between them doesn't lose ittokenVersion, embedded in each issued token and checked on every authenticated request — bumping it (from account settings' "התנתקות מכל המכשירים", or automatically on every password change/reset) instantly invalidates every token issued before that moment, everywhere, without needing a separate session store. A password change issues a fresh token for the device that just changed it, so that one stays logged in while every other session is cutAdmin
/admin/feedback) listing free-text suggestions/bug reports submitted by anyone (logged in or not), most recent first, with the sender's name/email when known or marked anonymous when not, and a delete action per entry so handled/irrelevant feedback doesn't pile up indefinitely| Backend | NestJS, TypeScript, Prisma ORM, PostgreSQL |
| Frontend | Next.js 16 (App Router), React 19, TypeScript, Tailwind CSS v4 |
| Auth | JWT (@nestjs/jwt), bcrypt |
| Testing | Jest + Supertest (unit/integration), Playwright (browser verification) |
apps/
api/ NestJS backend (REST API, Prisma schema & migrations)
web/ Next.js frontend
docker-compose.yml Local PostgreSQL
There's no root workspace config — each app is installed and run independently.
Prerequisites: Node.js 20+, Docker (for local Postgres) or an existing PostgreSQL instance.
# 1. Start Postgres
docker compose up -d
# 2. Backend
cd apps/api
npm install
cp .env.example .env # set DATABASE_URL and JWT_SECRET
npx prisma migrate dev
npm run db:seed # creates a seeded admin user, see below
npm run start:dev # http://localhost:3001
# 3. Frontend (separate terminal)
cd apps/web
npm install
npm run dev # http://localhost:3000
| App | Variable | Notes |
|---|---|---|
apps/api | DATABASE_URL | PostgreSQL connection string |
apps/api | JWT_SECRET | Secret used to sign auth tokens |
apps/api | PORT | Optional, defaults to 3001 |
apps/api | FRONTEND_URL | Optional. Allowed CORS origin, defaults to http://localhost:3000 — set to the real frontend URL on deploy |
apps/api | PUBLIC_APP_URL | Optional. Base URL used inside real email links (password reset, etc.) only — separate from FRONTEND_URL so local dev can send real emails (via a real RESEND_API_KEY) with links pointing at the real production site instead of localhost. Falls back to FRONTEND_URL, so production never needs to set it |
apps/api | GOOGLE_VISION_API_KEY | Optional. Face blurring works for free without this (local BlazeFace model) — this only adds a Cloud Vision fallback for photos the local model misses. Requires billing enabled on the Google Cloud project |
apps/api | RESEND_API_KEY | Optional. Real email delivery. Without a verified sending domain, real recipients get rejected by Resend and notifications fall back to a console log |
apps/api | R2_ACCOUNT_ID, R2_ACCESS_KEY_ID, R2_SECRET_ACCESS_KEY, R2_BUCKET_NAME, R2_PUBLIC_URL | Optional. Dress photo storage on Cloudflare R2. Without these (or if R2 is unreachable), uploads fall back to local disk under apps/api/uploads automatically — the app works fine either way |
apps/web | NEXT_PUBLIC_API_URL | Optional, defaults to http://localhost:3001 |
[email protected] / Admin123!dev
Change this before deploying anywhere reachable outside your own machine.
cd apps/api
npm test # unit + integration (Jest, Supertest)
npm run test:cov # with coverage
apps/web): Vercel, with the project's root directory set to apps/web. Set NEXT_PUBLIC_API_URL to the deployed API's URL.apps/api) + database: Railway (or any Node host + managed Postgres), with the service's root directory set to apps/api. Build command npm run build, start command npm run start:prod — this runs prisma migrate deploy before starting, so migrations apply automatically on every deploy. Set every variable from the environment variables table above, especially a real (non-default) JWT_SECRET, DATABASE_URL pointing at the production Postgres instance, and FRONTEND_URL pointing at the deployed frontend.apps/api/uploads) is a dev-environment safety net, not meant to hold real production photos long-term, since most Node hosts (Railway included) wipe the local filesystem on every redeploy.prisma migrate deploy build the schema; the seeded dev admin ([email protected]) is for local dev only, per the environment variables section above.ownerId before writing — a missing route guard alone would never be enough to leak data.pendingDetails JSON + pendingAction on child rows), so the public read path never has to branch on edit state — it simply never selects the pending fields.recommended/newest paginate at the database level, while price-sorted queries fetch all matches, sort in application code, and slice — trading one code path's efficiency for correctness rather than reaching for raw SQL.INTERESTED), which meant nothing stopped an owner from just arranging a rental off-platform and never touching the app at all. The fix wasn't a policy — it was making the renter the one who creates the INTERESTED row, with the owner responding rather than reporting, so the interaction actually has to happen on the platform to exist at all.NotificationsService.send(), which calls the real Resend API and falls back to a console log if that call fails or isn't configured. Every trigger site calls a named method on that service, never a provider directly, so the eventual "real domain verified, remove the fallback" change is one-file.