Javis OS
Javis OS는 기업가를 돕는 에이전시 AI로, 업무를 지원하고 함께 성장합니다
README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
多租户餐厅 SaaS 系统,支持扫码点餐、实时厨房显示、智能分单。 技术栈:Next.js 14 + Supabase + TypeScript + Tailwind CSS • 本地库:bash scripts/sync-local-supabase-env.sh(见下方「本地 Supabase」) • 云端库:在 .env.local 填入云项目配置(见下方 Supabase 初始化) 1. 前往 supabase.com 注册并创建新项目 2. 记录项目 URL 和 anon key(在 Project Settings → API 中) 推荐使用 Supabase CLI 推送迁移(按时间顺序): Schema 已 squash 为单文件 supabase/migrations/20240101000000_initial_schema.sql;新变更请追加带时间戳的新 migration,勿改 baseline。 如果远端是历史库且出现“表已存在但迁移未记录”,先执行 supabase migration repair 后再 supabase db push。README 전문 보기 ↗
多租户餐厅 SaaS 系统,支持扫码点餐、实时厨房显示、智能分单。
技术栈:Next.js 14 + Supabase + TypeScript + Tailwind CSS
npm install
cp .env.local.example .env.local
bash scripts/sync-local-supabase-env.sh(见下方「本地 Supabase」).env.local 填入云项目配置(见下方 Supabase 初始化)supabase start # 仅本地库需要
npm run dev # 本地 Docker Supabase(读 .env.local.dev)
npm run stage # 云端 stage 项目(读 .env.local.supabase)
npm run cloud # 云端 Supabase(读 .env.local)
在 .env.local 中填入:
NEXT_PUBLIC_SUPABASE_URL=https://xxxxxxxxxxxx.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
NEXT_PUBLIC_BASE_URL=http://localhost:3000
推荐使用 Supabase CLI 推送迁移(按时间顺序):
supabase login
supabase link --project-ref <your-project-ref>
supabase db push
Schema 已 squash 为单文件 supabase/migrations/20240101000000_initial_schema.sql;新变更请追加带时间戳的新 migration,勿改 baseline。
如果远端是历史库且出现“表已存在但迁移未记录”,先执行 supabase migration repair 后再 supabase db push。
执行 supabase/seed.sql 会自动创建本地演示账号与「巨好吃餐厅」菜单(来自云库快照,不含订单)。登录:[email protected] / localdev123。更新快照:node scripts/generate-juhaochi-seed.mjs。
本地 Supabase:.env.local.dev 仅在本机生成(已 gitignore,勿提交)。首次:
supabase start
bash scripts/sync-local-supabase-env.sh
npm run dev
npm run dev 会先加载 .env.local.dev;已注入的变量不会被 .env.local 覆盖。
云端 stage:npm run stage 使用 .env.local.supabase(联调 Supabase 项目 restaurant-ordering-dev)。
云端:npm run cloud 使用现有 .env.local(其他云 Supabase 项目)。
除 NEXT_PUBLIC_* 外,运营后台与 bootstrap 还需:
SUPABASE_SERVICE_ROLE_KEY:Supabase 项目 Settings → API → service_role secretADMIN_BOOTSTRAP_SECRET:长随机串;仅用于 首个运营账号 bootstrap(@mesa/ops 的 /ops/bootstrap),不再用于租户侧开新店租户 Web(@mesa/web)建议配置 NEXT_PUBLIC_OPS_APP_URL(运营后台公网 URL),以便 /auth/admin/register 自动跳转到 /ops/login。
在 Supabase Dashboard → Authentication → URL Configuration:
http://localhost:3000;上线后改为生产域名(如 Vercel)http://localhost:3000/auth/callback 与生产环境的 https://你的域名/auth/callback 都加入白名单@mesa/ops 登录后打开 创建餐厅(/ops/restaurants/new)。若尚无运营账号,先在 /ops/bootstrap 用 ADMIN_BOOTSTRAP_SECRET 创建首个运营账号(仅需一次)。.env.local(SUPABASE_SERVICE_ROLE_KEY)。/auth/login 登录后台(邮箱已在创建时标为已确认,无需验证链接)。旧路径 /auth/admin/register 已下线(跳转到运营登录)。POST /api/admin/create-restaurant 返回 410,请改用 POST /api/ops/restaurants。
建议在 Supabase → Authentication → Providers → Email 中关闭 Allow new users to sign up(禁止匿名 signUp),与上述流程一致。
Supabase 内置邮件不是给公开注册用的:在未配置 自定义 SMTP 时,Auth 只会给当前组织「Team」里成员的邮箱发信,其他地址会失败,表现为注册报错、Users 里没有新用户。见官方说明:Send emails with custom SMTP。
正式解决(推荐):
**若已配 Resend 仍失败:**发件人填的是 [email protected] 时,Resend 只允许发到你在 Resend 注册用的那个邮箱,不能给任意 Gmail 发确认信。请到 Resend Domains 添加并验证你自己的域名,然后把 Supabase 里的 Sender email 改成 noreply@你的域名(或任意 @你的域名 地址),再测注册。
仅本地试功能(不推荐上生产):
signUp 成功)**仅临时测一封内置邮件:**把测试邮箱加进 Supabase Organization → Team 成员(只适合验证模板,不适合真实用户注册)。
| 路径 | 说明 |
|---|---|
/ | 产品落地页 |
/auth/login | 统一登录(店主邮箱或员工登录名;一页 + POST /api/auth/login) |
/auth/register | 提示「公开注册已关闭」(跳转登录) |
/auth/admin/register | 已下线 — 重定向至运营后台 /ops/login(需 NEXT_PUBLIC_OPS_APP_URL) |
/dashboard | 餐厅后台概览 |
/dashboard/settings/menu | 菜单管理 |
/dashboard/tables | 桌位二维码管理 |
/dashboard/orders | 订单历史 |
/dashboard/settings | 餐厅设置 Hub(基本资料、员工管理、桌位、菜单等 Tab) |
/dashboard/settings/staff | 员工账号(创建、停用、删除、重置密码等) |
/[slug]/menu?table_id={uuid} | 顾客点餐页(手机端;QR 绑稳定 table_id,界面显示 display_name 如 A-01) |
/[slug]/staff/login | 店内扫码别名(同款统一登录 UI,带店名上下文) |
/auth/staff/login | 已合并 — 重定向至 /auth/login |
/auth/staff/change-password | 员工首次登录 / 重置密码后的强制改密 |
/[slug]/kitchen | 厨房显示页(需 已登录 的厨房角色员工) |
/[slug]/waiter | 服务员观察页(需 已登录 的服务员角色员工) |
/[slug]/bill?table_id={uuid} | 账单分单页 |
/[slug]/waiter/[tableId] | 服务员单桌详情(路径为桌位 UUID) |
table_id(UUID) 与展示名 display_name(如 A-01) 分离;改显示名 不重打 QR。print_jobs.payload 成对写入 table_id + display_name 快照;热敏纸 只印 display_name,UUID 仅用于日志/队列/重打。docs/restaurant-tables-design.zh.md;转台/并台见 docs/table-transfer-merge-plan.zh.md。/auth/login(或 店主从后台侧边栏打开看板,同一浏览器会话无需再录员工密码)后,页面通过 Supabase Realtime 订阅 orders 与 table_sessions,并在进入时 立即拉取 最新数据(未满足则跳转到登录页)。table_sessions 为 open 或 billing 时,对应 orders.session_id 会出现在后厨与服务员看板;餐次关闭后,这些订单从两页看板消失(无需整页刷新)。closed_reason = waiter_closed),用于未开做前撤台、错台等;已有出餐中的桌台需先跟随后厨流程或逐单处理。详见 docs/table-transfer-merge-plan.zh.md 中「服务员关台与看板可见性」。/dashboard/settings/staff;实施顺序与 CRUD/API/RLS 约定见 docs/staff-accounts-plan.md。git init && git add . && git commit -m "init"
git remote add origin <your-github-repo>
git push -u origin main
仓库为 npm workspaces:apps/web(租户产品)+ apps/ops(运营后台)。同一 main 分支、两个独立 Vercel Project,互不影响构建与回滚。详见 docs/monorepo-vercel.zh.md。
mesa-web(现有生产项目 — 须改 Root Directory)
apps/web → SaveNEXT_PUBLIC_SUPABASE_URL、NEXT_PUBLIC_SUPABASE_ANON_KEY、NEXT_PUBLIC_BASE_URLSUPABASE_SERVICE_ROLE_KEY(按需)、CRON_SECRET 等ADMIN_BOOTSTRAP_SECRET(归 ops 项目)mesa-ops(新建)
apps/opsmainSUPABASE_SERVICE_ROLE_KEY、ADMIN_BOOTSTRAP_SECRET、Supabase URL/anon key 等(见运营计划文档)两个项目的 vercel.json 已配置 ignoreCommand:仅改 apps/ops 时跳过 web 构建,反之亦然。
在 Supabase → Authentication → URL Configuration 中将 Site URL 更新为 Vercel 域名。
SUPABASE_SERVICE_ROLE_KEY 与 ADMIN_BOOTSTRAP_SECRET,在运营后台 /ops/bootstrap 创建首个运营账号,再在 /ops/restaurants/new 创建店主与餐厅(见 docs/platform-admin-plan.zh.md)。/auth/login 登录,在 /dashboard/settings/menu 添加菜品/dashboard/tables 生成桌位二维码并打印/dashboard/settings/staff 创建厨房 / 服务员员工账号(每人 {登录名}@mesa.in + 初始密码;登录名全平台唯一)/dashboard/tables 下载或打印 桌位二维码(店内登录二维码可指向 /[slug]/staff/login,与统一登录同款)/auth/login(或店内扫码别名),用登录名 + 密码登录;首次或重置后须完成 /auth/staff/change-password/[slug]/kitchen 或 /dashboard/waiter 进入对应看板(角色不匹配会提示错误)