尚未检测到更新。GitHub 发布版本后会显示在这里。
个人 GitHub 账号下公开仓库的所有者可以登录并验证所有权,自行管理介绍,无需管理员批准。
登录并生成验证文件,在 30 分钟内将其提交到此仓库的默认分支。其他分支或分叉仓库中的文件无效。然后在下方检查文件,即可无需管理员批准直接管理项目。请保留文件以维持管理权限。
如需登录,将前往登录页面。登录后请回到此处,再次点击所选的验证按钮。
在项目文件夹中运行 /nomorevibe verify,即可验证所有权并自行管理介绍。
一分钟完成验证正在加载完整 README。 以下为已保存的摘录。
A polished, mobile-first table-reservation widget + admin dashboard for a restaurant (demo brand: Terrazza, Tirana). Guests pick a date, party size and time; a table is assigned automatically; the guest and the owner both get an email confirmation, and the guest can cancel with one click from that email.
Designed to be dropped into an existing site — embedded as an iframe/widget or driven through its API — so the marketing website is intentionally not part of this project. Only the booking flow and the dashboard are.查看完整 README ↗A polished, mobile-first table-reservation widget + admin dashboard for a restaurant (demo brand: Terrazza, Tirana). Guests pick a date, party size and time; a table is assigned automatically; the guest and the owner both get an email confirmation, and the guest can cancel with one click from that email.
Designed to be dropped into an existing site — embedded as an iframe/widget or driven through its API — so the marketing website is intentionally not part of this project. Only the booking flow and the dashboard are.
/reserve) — mobile-first, two steps: date + party + time → your details. A suitable free table is assigned automatically./r/<token>) and cancels the booking./dashboard) — analytics, a live floor plan, reservations, tables, guests (CRM) and settings.Next.js 16 · TypeScript · Tailwind v4 · shadcn/ui · Prisma + SQLite (Postgres-ready) · React Hook Form + Zod · Recharts · Nodemailer · Server Actions.
npm install
npx prisma migrate deploy # or: npx prisma migrate dev
npm run db:seed # 11 tables, 24 guests, ~120 reservations
npm run dev # http://localhost:3000 → redirects to /reserve
Copy .env.example to .env and fill in SMTP to send real emails; without it the app runs in demo mode (notifications are recorded but not delivered).
There is no single "max per hour" number — capacity is driven by your tables, which is more accurate (a 2-top and an 8-top are different capacity). At any given time, the number of reservations you can hold =
the number of active tables that are free at that time and big enough for the party.
A booking holds its table for the seating duration plus a buffer before the next booking. So each physical table can host several sittings per shift.
You set the numbers in two places, all editable in the admin Settings and Tables pages:
| Value | Where | Effect |
|---|---|---|
| Number of tables & their seats | Tables page | The core cap — 11 tables = up to 11 concurrent reservations |
| Seating duration (e.g. 120 min) | Settings | How long each booking holds a table |
| Buffer between bookings (e.g. 15 min) | Settings | Gap for turning the table |
| Booking interval (e.g. 30 min) | Settings | Granularity of the offered time slots |
| Opening shifts (lunch/dinner) | Settings | Which times are bookable at all |
Example (the seed data): 11 tables, 120-min seating, 15-min buffer, dinner 18:00–23:00. At 20:00, if 6 tables are already occupied by bookings overlapping 20:00, the engine offers 5 remaining tables (matched to party size). A table booked at 18:00 frees up around 20:15, so it can take a second sitting at 20:30 — that's how one table yields multiple reservations across the evening.
To simply "hold more reservations at 8pm", add more tables (or a section) on the Tables page; to change how quickly tables turn, adjust the seating duration / buffer in Settings.
provider = "postgresql" in prisma/schema.prisma and regenerate the migration.DATABASE_URL, NEXT_PUBLIC_APP_URL and the SMTP vars in the Vercel project.prisma generate && prisma migrate deploy && next build.Paste this where the widget should appear (Custom HTML block / theme):
<script src="https://YOUR-DOMAIN/embed.js" data-origin="https://YOUR-DOMAIN"></script>
embed.js inserts a responsive iframe of /reserve and auto-resizes it to fit (no scrollbars) via postMessage.
All endpoints send CORS headers (configure allowed sites with ALLOWED_ORIGINS).
| Method | Endpoint | Purpose |
|---|---|---|
GET | /api/availability?date=YYYY-MM-DD&party=N | Available times for a date + party size |
POST | /api/reservations | Create a reservation (JSON body below) |
GET | /api/reservations/{token} | Read a reservation by its token |
POST | /api/reservations/{token}/cancel | Cancel a reservation |
Create body:
{ "start": "2026-09-05T18:00:00.000Z", "partySize": 2,
"firstName": "Andi", "lastName": "Hysa",
"phone": "+355 69 123 4567", "email": "[email protected]",
"notes": "" }
Response: { "ok": true, "reservationId": "...", "cancelToken": "...", "manageUrl": "https://YOUR-DOMAIN/r/..." }.
Price/availability are always validated server-side; a suitable free table is assigned automatically.
prisma/schema.prisma Models: RestaurantTable, Reservation, Customer,
OpeningHour, Closure, Notification, RestaurantSetting
src/lib/availability.ts Capacity-aware availability engine
src/lib/email.ts SMTP/demo email provider
src/lib/notifications.ts Guest + owner emails (confirm / cancel / reschedule)
src/app/reserve/ Guest booking flow
src/app/r/[token]/ Self-service manage / cancel page
src/app/dashboard/ Admin (floor, reservations, tables, guests, settings)
src/server/ Read queries + Server Actions