尚未偵測到更新。GitHub 發布版本後會顯示在這裡。
個人 GitHub 帳號下公開儲存庫的擁有者可以登入並驗證所有權,自行管理介紹,無需管理員核准。
登入並產生驗證檔案,在 30 分鐘內將其提交至此儲存庫的預設分支。其他分支或分叉儲存庫中的檔案無效。然後在下方檢查檔案,即可無需管理員核准直接管理專案。請保留檔案以維持管理權限。
如需登入,將前往登入頁面。登入後請回到此處,再次點擊所選的驗證按鈕。
在專案資料夾中執行 /nomorevibe verify,即可驗證所有權並自行管理介紹。
一分鐘完成驗證A booking platform for barbershops — browse services, schedule appointments, and manage bookings. Built with Next.js 16, React 19, Prisma ORM, and PostgreSQL (Supabase).
翻譯準備中
取自儲存庫 README
正在載入完整 README。
檢視完整 README ↗A multi-tenant SaaS for barbershops, built with Next.js, TypeScript, Prisma and PostgreSQL. Many shops run on one deployment, each at its own URL (/b/<slug>) with its own data, branding and staff. Clients have one global account: they find a shop on the landing page and book a service with a specific barber. Staff work in role-specific areas of their shop, and shops pay a monthly subscription through Stripe.
Live: vig-barber.vercel.app (billing runs in Stripe test mode, so use the test card 4242 4242 4242 4242)
For clients
For shop staff (roles come from a membership in each shop, so one person can be an admin in one shop and a client in another)
/painel ("Minhas barbearias") lists every shop a person works atFor the platform
/platform) to create, suspend and reactivate shops, invite owners, see each shop's billing status and extend trialsBilling
pg driver adapterslug (or from a row the user already owns, like their booking). A barbershopId sent by the browser is never trusted.barbershopId. Updates and deletes filter by both the record id and the shop id, then check that a row was actually changed.Membership per user and shop, and are read from the database on every request. Platform admins get no implicit access to shops.The full design and the migration from a single-shop app are in docs/multi-tenant-plan.md; billing is in docs/billing-plan.md.
git clone https://github.com/Gabriel-Vignoli/vig-barber.git
cd vig-barber
# Also generates the Prisma client into app/generated/prisma
npm install
cp .env.example .env
Fill in .env. Only the database and NextAuth variables are required to start; the other services turn themselves off while their keys are missing.
| Variable | What it is for |
|---|---|
DATABASE_URL | Transaction pooler (port 6543), used by the app |
DIRECT_URL | Session pooler (port 5432), used by the Prisma CLI |
NEXT_AUTH_SECRET | NextAuth session secret |
GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET | Google login |
RESEND_API_KEY, EMAIL_FROM | Password reset and invitation emails |
APP_URL | Absolute origin for links in emails (custom domain) |
UPLOADTHING_TOKEN | Shop logo and banner uploads |
CONTACT_EMAIL, CONTACT_WHATSAPP | Contact buttons on the landing page (hidden when unset) |
STRIPE_SECRET_KEY, STRIPE_WEBHOOK_SECRET, STRIPE_PRICE_BASIC | Subscriptions and the webhook |
# Apply migrations and seed 3 demo shops
npx prisma migrate dev
npx prisma db seed
npm run dev
Open http://localhost:3000. The demo users (a platform admin, shop owners, barbers, a front-desk user and clients) are listed in prisma/seed.ts. You choose their logins in .env: SEED_ADMIN_EMAIL and SEED_ADMIN_PASSWORD for the platform admin, SEED_PASSWORD for everyone else. A password left empty is generated at random and printed at the end of the seed.
Warning: the seed deletes every row in the database before it inserts the demo data. Never run it against a database with real shops.
To test billing locally, forward Stripe events to the webhook and put the secret it prints in STRIPE_WEBHOOK_SECRET:
stripe listen --forward-to localhost:3000/api/stripe/webhook --events checkout.session.completed,customer.subscription.created,customer.subscription.updated,customer.subscription.deleted,invoice.paid,invoice.payment_failed
Prisma 7:
migrate devno longer runsprisma generateor the seed. After you changeprisma/schema.prisma, runnpx prisma generateyourself. The CLI reads its settings fromprisma.config.ts.Connection errors? Some networks (school or corporate wifi) block port 6543. If you get P1017 (
Server has closed the connection) locally, try another network or point your localDATABASE_URLat the 5432 URL.
npm run test
The suite (400+ tests) runs against a throwaway PostgreSQL started by embedded-postgres, with the real migrations applied, so it needs no Docker and never touches your .env database. It covers cross-shop isolation for every mutation, booking rules and availability, reviews, invitations, plan limits, the billing gate and the Stripe webhook sync.
Before pushing: npm run lint, npm run build and npm run test.
vig-barber/
├── app/
│ ├── (landing)/ # Platform landing page and shop finder at /
│ ├── b/[slug]/ # One shop
│ │ ├── (client)/ # Shop home, service and barber pages
│ │ ├── admin/ # Admin panel (dashboard, services, staff, expenses, billing...)
│ │ ├── atendente/ # Front-desk walk-in screen and bookings
│ │ ├── staff/ # Barber's own bookings
│ │ └── assinatura-pendente/ # Shown to staff while the shop is unpaid
│ ├── platform/ # Super admin panel
│ ├── painel/ # "Minhas barbearias"
│ ├── convite/[token]/ # Accept an invitation
│ ├── login/ bookings/ profile/
│ ├── api/ # NextAuth, UploadThing and the Stripe webhook
│ ├── _actions/ # Server Actions, one per file
│ ├── _data/ # Server-only data fetchers used by pages
│ ├── _lib/ # Tenant helpers, auth, billing, Stripe, time logic, validations
│ └── components/ # Feature components (ui/ holds the shadcn primitives)
├── prisma/ # Schema, migrations and seed
├── tests/ # Vitest suite
├── docs/ # Multi-tenant and billing plans
├── prisma.config.ts # Prisma CLI config
└── proxy.ts # Requires a session on protected routes (roles are checked by pages)
Date math.{ ok, data } or { ok: false, error } instead, so the Portuguese messages reach the user.authorize(), so failed attempts are tracked by a separate Server Action called before sign-in.Decimal serialization: Prisma Decimal values are converted to number before they reach Client Components.Live and in active development. Billing still runs in Stripe test mode while the first shops try the system.