尚未检测到更新。GitHub 发布版本后会显示在这里。
个人 GitHub 账号下公开仓库的所有者可以登录并验证所有权,自行管理介绍,无需管理员批准。
登录并生成验证文件,在 30 分钟内将其提交到此仓库的默认分支。其他分支或分叉仓库中的文件无效。然后在下方检查文件,即可无需管理员批准直接管理项目。请保留文件以维持管理权限。
如需登录,将前往登录页面。登录后请回到此处,再次点击所选的验证按钮。
在项目文件夹中运行 /nomorevibe verify,即可验证所有权并自行管理介绍。
一分钟完成验证正在加载完整 README。 以下为已保存的摘录。
Table service for restaurants, from either side. A diner scans the QR at their
table, browses the menu, customises and pays (card / Apple Pay / Google Pay via
Stripe) — or a waiter takes the order on their own phone, carries the plates out
and collects the bill in cash, by card, in equal parts or a hundred pesos at a
time. There is a counter till for walk-ins, a kitchen board that keeps working
when the wifi does not, and tickets on paper for the pass.
Built with Next.js (App Router) · Supabase · Stripe.查看完整 README ↗Table service for restaurants, from either side. A diner scans the QR at their table, browses the menu, customises and pays (card / Apple Pay / Google Pay via Stripe) — or a waiter takes the order on their own phone, carries the plates out and collects the bill in cash, by card, in equal parts or a hundred pesos at a time. There is a counter till for walk-ins, a kitchen board that keeps working when the wifi does not, and tickets on paper for the pass. Regulars get a visit card with rewards, and customers the restaurant trusts can run an account and pay it later. A register-only plan (Caja) runs the till on its own, with a menu diners read on their phones and order at the counter.
Built with Next.js (App Router) · Supabase · Stripe.
📄 Product & technical spec: docs/SPEC.md — concept, flows,
data model, security, and the open decisions to make next.
supabase/{schema,seed,drop,purge}.sql ← DDL + seed + reset SQL (run via pnpm db:*)
scripts/ ← the gates: api, rls, roles, smoke, layout,
promises, money, attack, dialogs (pnpm <name>)
src/lib/supabase/{client,server,admin}.ts ← 3 Supabase clients (publishable + secret)
src/lib/csp.ts ← what the browser may load and talk to
src/middleware.ts ← refreshes auth sessions, writes the policy
src/lib/legal/ ← the terms and the aviso, and the PDFs built
from them (node scripts/legal-pdf.mjs)
src/app/r/[restaurantId]/t/[tableId]/ ← the diner's menu and bill (QR target)
src/app/order/[orderId]/ ← live order tracking
src/app/dashboard/orders/ ← the kitchen board, and what is ready to carry
src/app/dashboard/table-order/ ← the waiter's pad
src/app/dashboard/bills/ ← open bills, collecting, the calculator
src/app/dashboard/pos/ ← the counter till
src/app/dashboard/accounts/ ← customer accounts: open, charge, collect
src/app/dashboard/loyalty/ ← the visit card program
src/app/cuenta/[code]/ ← a customer's account statement (its QR)
src/app/rewards/ ← a diner's visit card, by its code
src/app/dashboard/[menu]/ ← menus, sections, products, extras
src/app/dashboard/{tables,promotions,analytics,settings,staff,plan,admin}/
src/app/api/checkout/ ← prices a cart and opens Stripe Checkout
src/app/api/webhooks/stripe{,/connect}/ ← the only place a payment is believed
src/app/api/table-{order,bill,payment}/ ← what the waiter takes and collects
src/app/api/print/cloudprnt/[token]/ ← what a kitchen printer asks for
src/app/globals.css ← design system
Requires Node ≥ 18.18 (Next.js 15). An
.nvmrcpins Node 22 — runnvm use.
This is a complete Next.js project — just install and go.
nvm use # or ensure your node is ≥ 18.18
corepack enable # makes the pinned pnpm available
pnpm install
The app uses two Supabase projects so development never touches production data. Config lives in per-environment files (all gitignored):
| File | Used by | Points at |
|---|---|---|
.env.development.local | pnpm dev, pnpm db:* | your dev Supabase project |
.env.production.local | pnpm build/start, pnpm db:*:prod | your prod Supabase project |
cp .env.development.local.example .env.development.local # fill in dev keys
cp .env.production.local.example .env.production.local # fill in prod keys (later)
Each needs the Supabase URL + keys, Stripe keys, and a DATABASE_URL (Supabase →
Connect → Session pooler URI, with your DB password). Next.js loads the
right file automatically based on NODE_ENV.
With DATABASE_URL set in .env.development.local:
pnpm db:reset # drop + create + seed the dev database, prints a demo URL
Database scripts (default = dev; append :prod to target production, which
prompts for confirmation on destructive ops):
| Command | What it does |
|---|---|
pnpm db:create | Create tables / RLS / realtime (structure only). |
pnpm db:seed | Insert the demo restaurant + menu, and (dev only) create the test logins below. Idempotent. |
pnpm db:reset | Drop + create + seed — a clean slate. Use this most. |
pnpm db:purge | Empty every table, keep the structure. |
pnpm db:drop | Drop all tables entirely. |
pnpm db:mock | Add a self-contained demo restaurant ("Demo Bistro") with a full menu, ~250 orders across 30 days, a named team, live orders and service requests — everything to present the app. Repeatable. |
pnpm db:dropmock | Remove only the demo data (Demo Bistro + its logins); leaves the base seed untouched. |
…:prod | Same, against the prod DB (e.g. pnpm db:create:prod, pnpm db:mock:prod). |
Prefer the dashboard? You can still paste
supabase/schema.sql(thensupabase/seed.sql) into the Supabase SQL Editor and Run.
pnpm dev
Restaurant: open http://localhost:3000/signup to create an account (this also
creates your restaurant), then you land on /dashboard. Sign in again any time
at http://localhost:3000/login.
Test logins (dev only): pnpm db:seed / pnpm db:reset create five ready
accounts, password test123, each with its own "Test Restaurant N" — and each
on a different plan, so every tier can be demonstrated by signing in rather
than by editing the database. These are never created on prod.
| login | plan | what it is for |
|---|---|---|
[email protected] | Carta (free) | The gates. Table QRs fall back to the counter menu, coupons and promotions are refused, the dish ceiling bites. It keeps the tables and dishes the seed built, which is what a real downgrade looks like. |
[email protected] | Servicio | The entry paid tier with tables: open bills, promotions, the visit card, customer accounts. No coupons, no menu schedules. |
[email protected] | Casa | Everything that is buyable — coupons, menu schedules, staff discounts, a year of analytics. |
[email protected] | Grupo | What the top tier unlocks, before the tier itself is finished. |
[email protected] | Servicio, trial expired yesterday | A lapsed trial without waiting thirty days for one: the app settles it to Carta on the first request, exactly as it would in life. |
Customer menu: http://localhost:3000/r/<restaurantId>/t/<tableId> — pnpm db:reset
prints a ready-to-open demo URL.
Presentation data: pnpm db:mock builds "Demo Bistro" — a fully populated
restaurant to demo every feature (orders board, analytics, service requests,
staff). Logins: [email protected] (owner), demo-manager@, demo-waiter@,
demo-cashier@, demo-kitchen@, password demo123. Run pnpm db:dropmock to remove it again.
Install the Stripe CLI, then forward webhooks to your local server:
stripe listen --forward-to localhost:3000/api/webhooks/stripe
Copy the whsec_... it prints into STRIPE_WEBHOOK_SECRET in
.env.development.local. Use test card 4242 4242 4242 4242, any future expiry,
any CVC.
Push to GitHub (you've done this).
vercel.com → Add New → Project → import your repo.
Under Environment Variables, add all the keys from your
.env.production.local (paste the secret values here directly — they live
only in Vercel, never in chat or git).
Deploy. You'll get a URL like https://tabletap.vercel.app.
Add BOTH production webhooks. There are two Stripe accounts in play, so there are two endpoints, each with its own signing secret:
| endpoint | register as | events |
|---|---|---|
/api/webhooks/stripe | events on your account | customer.subscription.* |
/api/webhooks/stripe/connect | events on connected accounts | checkout.session.completed, checkout.session.expired |
Their secrets go into Vercel as STRIPE_WEBHOOK_SECRET and
STRIPE_WEBHOOK_SECRET_CONNECT. The wrong one fails every event with a 400
that looks like a delivery problem. Until they exist a card payment never
marks its order paid — pnpm money:prod is the check that catches it.
See docs/before-launch.md for the rest of what only
the business can supply: live keys, a mail provider, and the legal identity.
src/lib/csp.ts): no inline script anywhere, and connect-src limited to us
and Supabase, so a script that somehow ran has nowhere to send a bill.pnpm rls attacks every tenant table as every role, and pnpm attack
asks what a signed-in person can do that they should not — judged on whether
a peso moved, never on the absence of an error.docs/SPEC.md — what the app is: the flows, the money, the
roles, and why each decision went the way it did.docs/regressions.md — every bug that has actually
shipped here, and what now catches each one automatically.docs/before-launch.md — the things outside the code
that only the business can supply, and what each one breaks while it is missing.CLAUDE.md — how code is written here, and the gate to run
before shipping anything.