Saleor Store
우리 컬렉션을 쇼핑하세요
토론토에서 검증된 애정 어린 펫시터·도그워커를 예약하세요. 신원 확인, 실시간 GPS 추적, 수의사 보장이 포함됩니다
Book verified, loving pet sitters and dog walkers near you in Toronto. Background-checked sitters, live GPS walk tracking and vet care coverage on every booking.
커머스TypeScript · JavaScriptGitHub @gokhanazp온라인운영자 미확인
써 보셨어요? 한 번만 눌러 주세요. 로그인은 필요 없어요.
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
Pet sitting & dog walking marketplace — Toronto first, Canada-wide later.
Next.js 16 (App Router) · Tailwind CSS 3 (design tokens from the Stitch "Warm Paw Companion" system) · Prisma · Supabase (Postgres, Auth, Storage).
Manual alternative: copy .env.example to .env, then npx prisma migrate deploy && npm run db:seed.
Demo accounts — each has its own random password, written to the git-ignored .demo-credentials file by the seed (or rotate them any time with node --env-file=.env node_modules/.bin/tsx scripts/rotate-demo-passwords.ts):README 전문 보기 ↗Pet sitting & dog walking marketplace — Toronto first, Canada-wide later. Next.js 16 (App Router) · Tailwind CSS 3 (design tokens from the Stitch "Warm Paw Companion" system) · Prisma · Supabase (Postgres, Auth, Storage).
npm install
# fill .env.supabase (DB password + access token, or keys + connection strings), then:
npm run supabase:setup # writes .env, sets Auth URLs, runs migrations, seeds demo data
npm run dev -- -p 3100
Manual alternative: copy .env.example to .env, then npx prisma migrate deploy && npm run db:seed.
Demo accounts — each has its own random password, written to the git-ignored .demo-credentials file by the seed (or rotate them any time with node --env-file=.env node_modules/.bin/tsx scripts/rotate-demo-passwords.ts):
| Account | Role | What to try |
|---|---|---|
[email protected] | Pet parent | /account/bookings (upcoming, completed + reviewed), /account/pets, /messages, book Sarah |
[email protected] | Sitter | /sitter — 2 pending requests to accept/decline, profile & rates editor |
[email protected] | Admin | /admin — approve application WS-31877, cities, fees, users, reviews |
Other sitters log in as <slug>@wagstays.ca; extra owners: [email protected], [email protected], [email protected].
| Path | What |
|---|---|
src/app/(site)/ | Public pages (header + footer layout) |
src/app/actions/ | Server actions (auth, favourites, booking, applications…) |
src/lib/queries.ts | Data access used by pages |
src/lib/pricing.ts | Single source of truth for booking prices (fees, WagPoints, HST) |
src/lib/session.ts | Local JWT cookie auth — to be replaced by Supabase Auth |
prisma/schema.prisma | Data model (Postgres-compatible; enum-like fields are strings) |
docs/LOCALIZATION.md | TR design → EN-CA copy, names, places, prices |
src/app/admin/ | Admin panel (requireAdmin): dashboard, applications, sitters, bookings, users, reviews, cities, settings, audit log |
src/app/(site)/account/ · sitter/ · messages/ | Pet parent area · sitter dashboard · messaging |
src/lib/auth.ts | requireUser / requireSitter / requireAdmin guards (every server action re-checks) |
src/lib/booking-lifecycle.ts | Allowed booking status transitions per actor, WagPoints refunds, rating recompute |
src/lib/settings.ts | Platform fees from PlatformSettings (edited in /admin/settings) |
src/lib/audit.ts | Admin audit trail |
src/proxy.ts | Redirects signed-out visitors away from private areas |
PENDING (owner requests) → CONFIRMED / DECLINED (sitter or admin) → COMPLETED (sitter or admin, after start) → owner can review.
CANCELLED by the owner (pending/confirmed), the sitter (confirmed) or an admin. WagPoints used are refunded on cancel/decline.
One pipeline, used by the profile widget, checkout, the booking server action (authoritative — it recomputes from DB prices) and /pricing:
src/lib/quote.ts → quoteBooking({ service, pets, dates, holidays }) — the sitter's part: base rate × units, extra pets (additionalPetPriceCents per pet after the first, per unit; null = one pet per booking, limit petLimit() = maxPetsPerBooking), holiday rate (holidayPriceCents replaces the base on statutory holidays from src/lib/holidays.ts, by City.provinceCode) and puppy surcharge (puppyPriceCents per pet under 1 year). Each line carries a kind (+ holiday name) and is stored in Booking.priceLines.src/lib/pricing.ts → priceBooking({ subtotalCents: quote.subtotalCents, taxRateBps, fees }) — adds the flat WagShield fee and service fee (PlatformSettings), subtracts WagPoints, then tax (City.taxRateBps). Weekly series: one quote + price per occurrence.src/lib/price-details.ts — plain-words copy on top (search badge "Up to 2 dogs · +$12 each", the profile "Price details" list in src/components/pricing/PriceDetails.tsx, line explanations for the InfoTip popovers). Search (searchSitters, petCount) only keeps services where petLimit(service) >= petCount.Demo add-on rates: node --env-file=.env node_modules/.bin/tsx scripts/demo-addon-rates.ts (idempotent, demo sitters only).
Only Toronto is active (City.isActive). Other cities are seeded inactive and are switched on from /admin/cities (a city needs at least one neighbourhood). Active cities automatically appear in the home search suggestions, the search location picker (/sitters?city=<slug>) and the sitter application form; approved sitters are placed in the city of the neighbourhood they applied for. Taxes come from City.taxRateBps, time zones from City.timeZone (date formatting still defaults to Toronto time — pass city.timeZone through when a second time zone goes live).
DATABASE_URL transaction pooler at runtime, DIRECT_URL session pooler for migrations). RLS is enabled on every table with no policies, so the public Data API exposes nothing — all reads/writes go through server code. Enable RLS on every new table in future migrations.User.id = auth.users.id; roles live in our User table, never in user-editable metadata. src/proxy.ts refreshes the session; getCurrentUser() in src/lib/session.ts is the only entry point pages use. Email links land on /auth/callback (PKCE code) or /auth/confirm (token hash). Suspending a user also bans them in Supabase Auth.media (public; pet, sitter and avatar photos) via src/lib/uploads.ts; bucket documents (private) is ready for ID / police-check files — the application form still stores only file names./admin/users/<id>.prisma/sqlite-archive/.GitHub Actions (.github/workflows/ci.yml) runs on every push and pull request to main:
npm ci, npx prisma generate, npx next typegen (route types aren't committed), npm run typecheck, npm run lint, npx next build. It uses dummy DATABASE_URL / DIRECT_URL / public Supabase values, so no secrets are needed — the build must never require a database. Pages that read data are rendered on demand; generateStaticParams and sitemap.ts fall back to an empty / static list when the DB isn't reachable.E2E_BASE_URL is set (e.g. https://wagstays.vercel.app). Installs Playwright Chromium and runs tests/e2e/smoke.spec.ts against that URL: anonymous pages only (home, /sitters, a sitter profile, /become-a-sitter, /login, /terms, /pet-sitters/<city>, sitemap.xml, robots.txt) — status 200, no console errors, valid JSON-LD. No credentials live in the repo and the tests never write data.Locally: npm run typecheck, npm run lint, npm run test:e2e (defaults to production; E2E_BASE_URL=http://localhost:3100 npm run test:e2e for the dev server; first run npx playwright install chromium).
src/app/sitemap.ts / src/app/robots.ts — origin from NEXT_PUBLIC_SITE_URL (see src/lib/seo/site.ts). The sitemap lists static pages, every active sitter in an active city and all neighbourhood landing pages; robots blocks the private areas (which also carry noindex)./pet-sitters/<city>, /pet-sitters/<city>/<hood>, /dog-walkers/<city>/<hood> (active cities only, 404 otherwise). Copy, prices, FAQ and structured data are generated from live data in src/lib/seo/landing.ts; park names per neighbourhood live in its PARKS map — extend it when a new city goes live.src/lib/seo/schema.ts (Organization + WebSite on every public page, LocalBusiness + offers + BreadcrumbList on sitter profiles, ItemList + FAQPage on landing pages).