尚未检测到更新。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.