Saleor Store
우리 컬렉션을 쇼핑하세요
MOTION X는 전 세계 자동차 구매자·개인 판매자·딜러를 연결하는 플랫폼으로, 몰입형 3D 전시장을 제공
MOTION X is a global automotive discovery platform connecting buyers, private sellers and professional dealerships across international markets — with immersive 3D showrooms.
커머스TypeScript · PLpgSQLGitHub @hannahfavour838-creator온라인운영자 미확인
써 보셨어요? 한 번만 눌러 주세요. 로그인은 필요 없어요.
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기A premium global automotive marketplace
저장소 README에서 가져옴
README 전체를 불러오는 중입니다.
README 전문 보기 ↗A premium international automotive marketplace with a cinematic real-time 3D hero, an interactive 3D showroom, real search and filtering, buyer accounts, private-seller and dealership tools, and a moderated administration area.
Stack: Next.js 16 (App Router, Turbopack) · React 19 · TypeScript · Tailwind CSS 4 · Three.js · React Three Fiber · drei · GSAP + ScrollTrigger · Supabase (Auth, Postgres, Storage) · Vercel.
npm install
cp .env.example .env.local # optional — the site runs without it
npm run dev # http://localhost:3000
Without Supabase credentials the app runs in preview mode: the marketplace, search, filters, vehicle pages, collections, compare and the 3D showroom all work against clearly-labelled demonstration inventory. Accounts, enquiries, seller tools and admin show an explanatory notice until Supabase is configured.
| Command | What it does |
|---|---|
npm run dev | Development server |
npm run build / npm start | Production build / server |
npm run lint · npm run typecheck | ESLint · TypeScript |
npm run db:test | Applies all migrations + seed to a throwaway local PostgreSQL and runs the security test suite |
npm run db:test:pglite | Same suite on PGlite (PostgreSQL compiled to WASM) — no PostgreSQL install needed. TWICE=1 also checks the hardening migration is idempotent |
npm run test:e2e | Playwright end-to-end tests (BASE_URL=http://localhost:3000; set CHROMIUM_PATH if needed) |
npm run test:unit | Unit tests for security helpers (safe redirects) |
npm run test:a11y | axe-core WCAG 2.1 A/AA audit of public pages at desktop and mobile widths (BASE_URL, CHROMIUM_PATH) |
npm run seed:generate | Regenerates supabase/seed.sql from the demo inventory |
npm run admin:grant -- [email protected] | Grants admin rights (needs the service-role key) |
npm run photos | Downloads the demo-listing photographs listed in tools/photos/manifest.mjs from Wikimedia Commons, blurs plates, crops and writes WebP + credits |
npm run renders | Re-renders the hero/showroom fallback stills of the 3D concept car |
.env.local (see .env.example).supabase link then supabase db push) or by pasting each file into the SQL editor:
supabase/migrations/20261009000000_core_schema.sql — tables, triggers, RLS policies, search functionsupabase/migrations/20261009000100_storage.sql — vehicle-images and dealer-logos buckets + policiessupabase/migrations/20261009000200_showroom_assets.sql — the licensed 3D concept-car assetsupabase/migrations/20261009000300_hardening.sql — security hardening (USD reference protection, anonymous quotas, upload ownership, function permissions)supabase/seed.sql, and set NEXT_PUBLIC_SHOW_DEMO_INVENTORY=true. Do not run the seed in production. Remove demo data any time with
delete from auth.users where email like '%@demo.motionx.invalid';
If you loaded an older seed (with /renders/demo/ images), run that delete and re-run supabase/seed.sql to pick up the photographs.NEXT_PUBLIC_SITE_URL; add https://your-domain/auth/callback to Redirect URLs.?code=); token-hash templates pointing at /auth/callback?token_hash={{ .TokenHash }}&type=… also work.insert into public.admin_users (user_id, note)
select id, 'founder' from auth.users where email = '[email protected]';
or npm run admin:grant -- [email protected].active/sold listings from active sellers. Enquiries and inspection requests are readable only by the buyer, the receiving seller and admins. Buyer profiles and private contact data are never public.admin_users, which no client can write.pending_review; material edits to a live listing return it to review (platform_settings.listing_moderation = required | auto). Every status change is written to moderation_actions.private.consume_rate_limit, not exposed via the API).npm run db:test exercises all of this against real PostgreSQL (91 assertions; Supabase's auth/storage schemas are stubbed — see supabase/tests/00_supabase_stubs.sql).
Original asking prices are always shown unchanged in the seller's currency. To enable clearly-labelled estimates and cross-currency price filtering/sorting:
EXCHANGE_RATES_PROVIDER=open-er-api (ExchangeRate-API open access — includes AED) or frankfurter (ECB reference rates — no AED).SUPABASE_SERVICE_ROLE_KEY and CRON_SECRET. vercel.json schedules /api/cron/exchange-rates daily; it stores rates and recalculates each listing's USD reference price.Without a provider, the price filter compares listings in the selected currency only, and says so on the page.
Set NEXT_PUBLIC_PLAUSIBLE_DOMAIN to enable cookieless Plausible analytics. Events: search, listing_view, enquiry_submitted, inspection_requested, buyer_signup, seller_signup, listing_submitted, dealer_onboarding, showroom_open. No personal data is sent; visitors can opt out at /cookies.
Full launch checklist (accounts, every environment variable, database, domain and post-deploy smoke test): DEPLOYMENT.md.
.env.example (at least the Supabase URL/key and NEXT_PUBLIC_SITE_URL).vercel.json activates automatically when CRON_SECRET is set./models/* is served with immutable caching — if you replace the GLB, give it a new filename and update vehicle_3d_assets.url.
| Asset | Source | Licence | Action needed |
|---|---|---|---|
public/models/concept-car.glb (hero + showroom) | “Car Concept” by Eric Chadwick / Darmstadt Graphics Group GmbH (2024), from the Khronos glTF-Sample-Assets repository, based on a CC0 model by “Unity Fan” | CC BY 4.0 — attribution required | Keep the credit on /credits and the showroom page. Khronos logo surfaces were removed; textures recompressed (WebP, 1024 px) and geometry meshopt-compressed: 11.8 MB → 3.4 MB. |
public/photos/demo/*, public/photos/banners/* | Wikimedia Commons photographs of the same make, model and generation as each demo listing (author and licence per file in src/lib/demo/photos.generated.json) | CC BY / CC BY-SA / public domain | Credited under each photo and on /credits. Labelled "Representative photo — not the vehicle listed". Plates blurred, cropped/extended to 3:2, WebP. Regenerate with npm run photos. |
public/renders/hero-fallback*.webp, OG image | Captured from the live hero scene (tools/qa/capture-poster.mjs) | Derived from the CC BY model | — |
Adding a 3D model to a listing: upload a licensed .glb (meshopt or uncompressed; not Draco), insert a vehicle_3d_assets row with credit/licence and supported paint_options, then set vehicles.asset_id. Only listings with an asset show the 3D action. Paint swatches appear only when the asset declares them; the runtime recolours materials whose names start with Paint 1.
src/app/(site)/ Pages: home, /cars, /cars/[slug], /collections, /showroom, /sell, /dealers,
/account, /dashboard, /admin, auth & legal pages
src/app/actions/ Server actions (public forms, auth, seller tools, admin)
src/app/api/cron/ Exchange-rate job
src/components/ Design system (ui/), home, vehicles, three (R3F), dashboard, admin, forms
src/config/ Site, markets (countries/currencies), vehicle taxonomy & collections
src/lib/data/ Data access (Supabase or demo backend), mappers
src/lib/ Auth (DAL), validation (zod), rates, rate limiting, analytics
supabase/ Migrations, seed, database tests
tools/photos/ Demo-listing photo pipeline (Commons → plates blurred → WebP + credits)
tools/studio-renderer/ Renderer for the 3D concept car's fallback stills
tools/qa/ Playwright E2E tests, screenshots, poster capture
npm run db:test:pglite (PGlite / PostgreSQL 18.3), not yet on a real Supabase project.npm run lint, npm run typecheck and npm run build pass./contact), not self-service.